about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml124
-rw-r--r--.gitignore2
-rw-r--r--.mailmap3
-rw-r--r--Cargo.lock81
-rw-r--r--RELEASES.md3
-rw-r--r--compiler/rustc_ast/src/ast.rs9
-rw-r--r--compiler/rustc_ast/src/format.rs4
-rw-r--r--compiler/rustc_ast/src/util/parser.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs64
-rw-r--r--compiler/rustc_ast_lowering/src/format.rs238
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs2
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs50
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs7
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs19
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs92
-rw-r--r--compiler/rustc_borrowck/src/lib.rs3
-rw-r--r--compiler/rustc_borrowck/src/nll.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs4
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs9
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs79
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs53
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml64
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml59
-rw-r--r--compiler/rustc_codegen_cranelift/.gitignore1
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock49
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml14
-rw-r--r--compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock15
-rw-r--r--compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/prepare.rs29
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/tests.rs51
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs11
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs381
-rw-r--r--compiler/rustc_codegen_cranelift/example/std_example.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch4
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch (renamed from compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch)15
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0023-coretests-Ignore-failing-tests.patch (renamed from compiler/rustc_codegen_cranelift/patches/0023-sysroot-Ignore-failing-tests.patch)12
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch30
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch (renamed from compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch)15
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0028-coretests-Disable-long-running-tests.patch (renamed from compiler/rustc_codegen_cranelift/patches/0028-sysroot-Disable-long-running-tests.patch)6
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs7
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/rustup.sh37
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh4
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh7
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs98
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/returning.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/analyze.rs30
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs33
-rw-r--r--compiler/rustc_codegen_cranelift/src/cast.rs50
-rw-r--r--compiler/rustc_codegen_cranelift/src/codegen_i128.rs85
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/compiler_builtins.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/cranelift_native.rs248
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/global_asm.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs155
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs9
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs15
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/num.rs39
-rw-r--r--compiler/rustc_codegen_cranelift/src/pointer.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/src/pretty_clif.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs34
-rw-r--r--compiler/rustc_codegen_cranelift/src/vtable.rs21
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs23
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs15
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/glue.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs11
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs8
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs4
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs7
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs5
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs9
-rw-r--r--compiler/rustc_data_structures/Cargo.toml13
-rw-r--r--compiler/rustc_data_structures/src/flock.rs5
-rw-r--r--compiler/rustc_data_structures/src/flock/windows.rs64
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs19
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs33
-rw-r--r--compiler/rustc_data_structures/src/vec_map.rs192
-rw-r--r--compiler/rustc_data_structures/src/vec_map/tests.rs48
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml7
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs8
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0206.md8
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0416.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0794.md64
-rw-r--r--compiler/rustc_errors/Cargo.toml10
-rw-r--r--compiler/rustc_errors/src/lib.rs2
-rw-r--r--compiler/rustc_errors/src/lock.rs81
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs24
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs2
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs6
-rw-r--r--compiler/rustc_hir/src/definitions.rs6
-rw-r--r--compiler/rustc_hir/src/hir.rs8
-rw-r--r--compiler/rustc_hir/src/hir_id.rs6
-rw-r--r--compiler/rustc_hir/src/intravisit.rs1
-rw-r--r--compiler/rustc_hir/src/lang_items.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs44
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs49
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs85
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs63
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs143
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs97
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs44
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs37
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/mod.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/test.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/variance/test.rs2
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs34
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs75
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs20
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs157
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs31
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs3
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs2
-rw-r--r--compiler/rustc_infer/src/infer/at.rs155
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs24
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs26
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs38
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs5
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs6
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs4
-rw-r--r--compiler/rustc_infer/src/infer/lattice.rs6
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs4
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs43
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs22
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs5
-rw-r--r--compiler/rustc_infer/src/infer/type_variable.rs5
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs10
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_lint/messages.ftl3
-rw-r--r--compiler/rustc_lint/src/builtin.rs30
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs11
-rw-r--r--compiler/rustc_lint/src/internal.rs2
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/lints.rs30
-rw-r--r--compiler/rustc_lint/src/map_unit_fn.rs11
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs6
-rw-r--r--compiler/rustc_lint/src/reexports.rs82
-rw-r--r--compiler/rustc_lint/src/unused.rs31
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs7
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs76
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs5
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs28
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs43
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs5
-rw-r--r--compiler/rustc_metadata/src/rmeta/table.rs27
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs10
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs14
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs97
-rw-r--r--compiler/rustc_middle/src/mir/patch.rs4
-rw-r--r--compiler/rustc_middle/src/mir/query.rs4
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs14
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs1
-rw-r--r--compiler/rustc_middle/src/query/keys.rs290
-rw-r--r--compiler/rustc_middle/src/query/mod.rs12
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs15
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs8
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs14
-rw-r--r--compiler/rustc_middle/src/ty/context.rs23
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs15
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs20
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs52
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs1
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/query.rs29
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs16
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs4
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs5
-rw-r--r--compiler/rustc_middle/src/ty/util.rs31
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs22
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs144
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs25
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs16
-rw-r--r--compiler/rustc_mir_build/src/build/misc.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs19
-rw-r--r--compiler/rustc_mir_build/src/lints.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs16
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs133
-rw-r--r--compiler/rustc_mir_transform/src/check_const_item_mutation.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs2
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs48
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs35
-rw-r--r--compiler/rustc_mir_transform/src/deduce_param_attrs.rs11
-rw-r--r--compiler/rustc_mir_transform/src/deref_separator.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/ffi_unwind_calls.rs7
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs15
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs27
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs59
-rw-r--r--compiler/rustc_mir_transform/src/nrvo.rs2
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs136
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs15
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs9
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs22
-rw-r--r--compiler/rustc_parse_format/src/lib.rs54
-rw-r--r--compiler/rustc_passes/Cargo.toml1
-rw-r--r--compiler/rustc_passes/messages.ftl21
-rw-r--r--compiler/rustc_passes/src/check_attr.rs173
-rw-r--r--compiler/rustc_passes/src/check_const.rs4
-rw-r--r--compiler/rustc_passes/src/dead.rs4
-rw-r--r--compiler/rustc_passes/src/debugger_visualizer.rs8
-rw-r--r--compiler/rustc_passes/src/diagnostic_items.rs7
-rw-r--r--compiler/rustc_passes/src/errors.rs45
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs2
-rw-r--r--compiler/rustc_passes/src/layout_test.rs2
-rw-r--r--compiler/rustc_passes/src/liveness.rs7
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs7
-rw-r--r--compiler/rustc_passes/src/stability.rs12
-rw-r--r--compiler/rustc_privacy/src/lib.rs8
-rw-r--r--compiler/rustc_query_impl/src/lib.rs2
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs18
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs94
-rw-r--r--compiler/rustc_query_system/src/dep_graph/mod.rs22
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs71
-rw-r--r--compiler/rustc_resolve/src/imports.rs54
-rw-r--r--compiler/rustc_resolve/src/late.rs5
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs48
-rw-r--r--compiler/rustc_session/Cargo.toml8
-rw-r--r--compiler/rustc_session/src/cstore.rs7
-rw-r--r--compiler/rustc_session/src/filesearch.rs47
-rw-r--r--compiler/rustc_session/src/options.rs3
-rw-r--r--compiler/rustc_session/src/utils.rs9
-rw-r--r--compiler/rustc_span/src/hygiene.rs2
-rw-r--r--compiler/rustc_span/src/source_map.rs31
-rw-r--r--compiler/rustc_span/src/symbol.rs4
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs4
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/riscv64gc_unknown_fuchsia.rs19
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs35
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly.rs47
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonical/mod.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs343
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs292
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs151
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs129
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs42
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs53
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs72
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs45
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs103
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs65
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs110
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs43
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs139
-rw-r--r--compiler/rustc_ty_utils/src/common_traits.rs3
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs1
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs6
-rw-r--r--compiler/rustc_ty_utils/src/representability.rs4
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs76
-rw-r--r--config.example.toml9
-rw-r--r--library/alloc/src/lib.rs4
-rw-r--r--library/alloc/src/rc.rs4
-rw-r--r--library/alloc/src/sync.rs4
-rw-r--r--library/alloc/src/vec/mod.rs13
-rw-r--r--library/alloc/tests/str.rs26
-rw-r--r--library/core/src/error.rs4
-rw-r--r--library/core/src/ffi/c_str.rs8
-rw-r--r--library/core/src/fmt/mod.rs32
-rw-r--r--library/core/src/fmt/rt/v1.rs6
-rw-r--r--library/core/src/future/mod.rs6
-rw-r--r--library/core/src/hash/mod.rs4
-rw-r--r--library/core/src/intrinsics.rs16
-rw-r--r--library/core/src/intrinsics/mir.rs2
-rw-r--r--library/core/src/iter/mod.rs2
-rw-r--r--library/core/src/iter/range.rs32
-rw-r--r--library/core/src/iter/traits/accum.rs40
-rw-r--r--library/core/src/iter/traits/double_ended.rs11
-rw-r--r--library/core/src/iter/traits/iterator.rs31
-rw-r--r--library/core/src/iter/traits/marker.rs3
-rw-r--r--library/core/src/lib.rs7
-rw-r--r--library/core/src/macros/mod.rs4
-rw-r--r--library/core/src/marker.rs5
-rw-r--r--library/core/src/net/socket_addr.rs26
-rw-r--r--library/core/src/num/dec2flt/common.rs1
-rw-r--r--library/core/src/num/dec2flt/float.rs4
-rw-r--r--library/core/src/num/dec2flt/lemire.rs2
-rw-r--r--library/core/src/num/dec2flt/mod.rs11
-rw-r--r--library/core/src/num/dec2flt/number.rs1
-rw-r--r--library/core/src/ops/try_trait.rs9
-rw-r--r--library/core/src/option.rs108
-rw-r--r--library/core/src/panicking.rs4
-rw-r--r--library/core/src/pin.rs35
-rw-r--r--library/core/src/primitive_docs.rs2
-rw-r--r--library/core/src/ptr/mod.rs59
-rw-r--r--library/core/src/slice/iter.rs4
-rw-r--r--library/core/src/slice/mod.rs2
-rw-r--r--library/core/src/str/iter.rs4
-rw-r--r--library/core/src/str/mod.rs10
-rw-r--r--library/core/src/sync/atomic.rs45
-rw-r--r--library/core/tests/fmt/mod.rs8
-rw-r--r--library/core/tests/iter/consts.rs36
-rw-r--r--library/core/tests/iter/mod.rs2
-rw-r--r--library/core/tests/lib.rs3
-rw-r--r--library/std/src/fs/tests.rs20
-rw-r--r--library/std/src/io/mod.rs18
-rw-r--r--library/std/src/io/stdio.rs13
-rw-r--r--library/std/src/net/tcp.rs10
-rw-r--r--library/std/src/net/tcp/tests.rs28
-rw-r--r--library/std/src/os/android/net.rs4
-rw-r--r--library/std/src/os/fd/owned.rs2
-rw-r--r--library/std/src/os/fd/raw.rs2
-rw-r--r--library/std/src/os/linux/net.rs4
-rw-r--r--library/std/src/os/net/linux_ext/addr.rs6
-rw-r--r--library/std/src/os/net/linux_ext/mod.rs2
-rw-r--r--library/std/src/os/unix/net/addr.rs4
-rw-r--r--library/std/src/os/unix/net/datagram.rs9
-rw-r--r--library/std/src/os/unix/net/listener.rs3
-rw-r--r--library/std/src/os/unix/net/stream.rs3
-rw-r--r--library/std/src/panic.rs3
-rw-r--r--library/std/src/primitive_docs.rs2
-rw-r--r--library/std/src/process.rs10
-rw-r--r--library/std/src/process/tests.rs34
-rw-r--r--library/std/src/sync/mpmc/array.rs107
-rw-r--r--library/std/src/sync/mpmc/mod.rs4
-rw-r--r--library/std/src/sync/mpsc/sync_tests.rs13
-rw-r--r--library/std/src/sync/remutex.rs2
-rw-r--r--library/std/src/sys/mod.rs9
-rw-r--r--library/std/src/sys/sgx/fd.rs6
-rw-r--r--library/std/src/sys/sgx/net.rs6
-rw-r--r--library/std/src/sys/unix/fd.rs9
-rw-r--r--library/std/src/sys/unix/net.rs28
-rw-r--r--library/std/src/sys/unix/pipe.rs6
-rw-r--r--library/std/src/sys/unix/stdio.rs6
-rw-r--r--library/std/src/sys/unsupported/net.rs6
-rw-r--r--library/std/src/sys/unsupported/pipe.rs6
-rw-r--r--library/std/src/sys/wasi/fd.rs18
-rw-r--r--library/std/src/sys/wasi/fs.rs2
-rw-r--r--library/std/src/sys/wasi/net.rs6
-rw-r--r--library/std/src/sys/windows/args.rs23
-rw-r--r--library/std/src/sys/windows/c.rs87
-rw-r--r--library/std/src/sys/windows/fs.rs12
-rw-r--r--library/std/src/sys/windows/handle.rs9
-rw-r--r--library/std/src/sys/windows/net.rs28
-rw-r--r--library/std/src/sys/windows/path.rs65
-rw-r--r--library/std/src/sys/windows/pipe.rs24
-rw-r--r--library/std/src/sys/windows/process.rs12
-rw-r--r--library/std/src/sys_common/net.rs6
-rw-r--r--library/test/src/console.rs83
-rw-r--r--library/test/src/formatters/json.rs52
-rw-r--r--library/test/src/formatters/junit.rs14
-rw-r--r--library/test/src/formatters/mod.rs6
-rw-r--r--library/test/src/formatters/pretty.rs29
-rw-r--r--library/test/src/formatters/terse.rs14
-rw-r--r--library/test/src/tests.rs200
-rw-r--r--library/test/src/types.rs10
-rw-r--r--src/bootstrap/CHANGELOG.md1
-rw-r--r--src/bootstrap/Cargo.lock76
-rw-r--r--src/bootstrap/Cargo.toml26
-rw-r--r--src/bootstrap/bin/rustc.rs52
-rw-r--r--src/bootstrap/bootstrap_test.py39
-rw-r--r--src/bootstrap/builder.rs8
-rw-r--r--src/bootstrap/compile.rs6
-rw-r--r--src/bootstrap/config.rs22
-rwxr-xr-xsrc/bootstrap/configure.py417
-rw-r--r--src/bootstrap/defaults/config.codegen.toml2
-rw-r--r--src/bootstrap/defaults/config.user.toml4
-rw-r--r--src/bootstrap/dist.rs4
-rw-r--r--src/bootstrap/install.rs11
-rw-r--r--src/bootstrap/job.rs85
-rw-r--r--src/bootstrap/lib.rs31
-rw-r--r--src/bootstrap/metrics.rs44
-rw-r--r--src/bootstrap/native.rs11
-rw-r--r--src/bootstrap/render_tests.rs376
-rw-r--r--src/bootstrap/tarball.rs1
-rw-r--r--src/bootstrap/test.rs53
-rw-r--r--src/bootstrap/util.rs86
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile9
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile4
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh2
-rw-r--r--src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile5
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile4
-rw-r--r--src/ci/github-actions/ci.yml4
-rwxr-xr-xsrc/ci/run.sh9
-rw-r--r--src/ci/stage-build.py4
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md4
-rw-r--r--src/librustdoc/Cargo.toml4
-rw-r--r--src/librustdoc/clean/blanket_impl.rs5
-rw-r--r--src/librustdoc/clean/mod.rs16
-rw-r--r--src/librustdoc/docfs.rs28
-rw-r--r--src/librustdoc/doctest.rs10
-rw-r--r--src/librustdoc/html/format.rs22
-rw-r--r--src/librustdoc/html/highlight.rs59
-rw-r--r--src/librustdoc/html/markdown.rs14
-rw-r--r--src/librustdoc/html/render/context.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs91
-rw-r--r--src/librustdoc/html/render/search_index.rs9
-rw-r--r--src/librustdoc/html/sources.rs60
-rw-r--r--src/librustdoc/html/static/js/search.js96
-rw-r--r--src/librustdoc/html/templates/STYLE.md14
-rw-r--r--src/librustdoc/html/templates/short_item_info.html2
-rw-r--r--src/librustdoc/html/templates/source.html19
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/visit_ast.rs8
-rw-r--r--src/stage0.json796
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs11
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs21
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs1
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.stdout6
-rw-r--r--src/tools/compiletest/Cargo.toml8
-rw-r--r--src/tools/compiletest/src/common.rs4
-rw-r--r--src/tools/compiletest/src/header.rs10
-rw-r--r--src/tools/compiletest/src/main.rs14
-rw-r--r--src/tools/compiletest/src/read2.rs4
-rw-r--r--src/tools/compiletest/src/runtest.rs57
-rw-r--r--src/tools/miri/.github/workflows/ci.yml8
-rw-r--r--src/tools/miri/CONTRIBUTING.md11
-rw-r--r--src/tools/miri/README.md151
-rwxr-xr-xsrc/tools/miri/ci.sh4
-rwxr-xr-xsrc/tools/miri/miri9
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs10
-rw-r--r--src/tools/miri/src/borrow_tracker/mod.rs70
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs592
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs539
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs307
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs554
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs304
-rw-r--r--src/tools/miri/src/diagnostics.rs14
-rw-r--r--src/tools/miri/src/eval.rs4
-rw-r--r--src/tools/miri/src/helpers.rs20
-rw-r--r--src/tools/miri/src/lib.rs2
-rw-r--r--src/tools/miri/src/machine.rs8
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs41
-rw-r--r--src/tools/miri/src/shims/intrinsics/mod.rs4
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs67
-rw-r--r--src/tools/miri/src/shims/unix/linux/fd.rs15
-rw-r--r--src/tools/miri/src/shims/unix/linux/fd/epoll.rs8
-rw-r--r--src/tools/miri/src/shims/unix/linux/fd/event.rs4
-rw-r--r--src/tools/miri/src/shims/unix/linux/fd/socketpair.rs4
-rw-r--r--src/tools/miri/src/shims/windows/dlsym.rs69
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs68
-rw-r--r--src/tools/miri/tests/compiletest.rs6
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs2
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/alternate-read-write.rs19
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr14
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/fragile-data-race.rs42
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr14
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/outside-range.rs22
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/outside-range.stderr19
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/read-to-local.rs14
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr14
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.rs34
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.stderr28
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.rs32
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.stderr28
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/retag-data-race.rs28
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/retag-data-race.stderr25
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/write-during-2phase.rs27
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr26
-rw-r--r--src/tools/miri/tests/pass/adjacent-allocs.rs2
-rw-r--r--src/tools/miri/tests/pass/associated-const.rs2
-rw-r--r--src/tools/miri/tests/pass/assume_bug.rs2
-rw-r--r--src/tools/miri/tests/pass/atomic.rs2
-rw-r--r--src/tools/miri/tests/pass/available-parallelism.rs2
-rw-r--r--src/tools/miri/tests/pass/box-custom-alloc.rs2
-rw-r--r--src/tools/miri/tests/pass/box.rs2
-rw-r--r--src/tools/miri/tests/pass/box.stack.stderr (renamed from src/tools/miri/tests/pass/box.stderr)0
-rw-r--r--src/tools/miri/tests/pass/box.stack.stdout (renamed from src/tools/miri/tests/pass/box.stdout)0
-rw-r--r--src/tools/miri/tests/pass/box.tree.stdout3
-rw-r--r--src/tools/miri/tests/pass/btreemap.rs2
-rw-r--r--src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs2
-rw-r--r--src/tools/miri/tests/pass/concurrency/channels.rs2
-rw-r--r--src/tools/miri/tests/pass/concurrency/sync.rs2
-rw-r--r--src/tools/miri/tests/pass/concurrency/sync.stack.stdout (renamed from src/tools/miri/tests/pass/concurrency/sync.stdout)0
-rw-r--r--src/tools/miri/tests/pass/concurrency/sync.tree.stdout20
-rw-r--r--src/tools/miri/tests/pass/concurrency/thread_locals.rs2
-rw-r--r--src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs3
-rw-r--r--src/tools/miri/tests/pass/concurrency/tls_lib_drop.stack.stdout (renamed from src/tools/miri/tests/pass/concurrency/tls_lib_drop.stdout)0
-rw-r--r--src/tools/miri/tests/pass/concurrency/tls_lib_drop.tree.stdout5
-rw-r--r--src/tools/miri/tests/pass/disable-alignment-check.rs2
-rw-r--r--src/tools/miri/tests/pass/dyn-arbitrary-self.rs2
-rw-r--r--src/tools/miri/tests/pass/extern_types.rs2
-rw-r--r--src/tools/miri/tests/pass/extern_types.stack.stderr (renamed from src/tools/miri/tests/pass/extern_types.stderr)0
-rw-r--r--src/tools/miri/tests/pass/float.rs30
-rw-r--r--src/tools/miri/tests/pass/future-self-referential.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs)3
-rw-r--r--src/tools/miri/tests/pass/generator.rs2
-rw-r--r--src/tools/miri/tests/pass/hashmap.rs2
-rw-r--r--src/tools/miri/tests/pass/intptrcast.rs2
-rw-r--r--src/tools/miri/tests/pass/linked-list.rs2
-rw-r--r--src/tools/miri/tests/pass/many_shr_bor.rs2
-rw-r--r--src/tools/miri/tests/pass/memleak_ignored.rs2
-rw-r--r--src/tools/miri/tests/pass/option_box_transmute_ptr.rs2
-rw-r--r--src/tools/miri/tests/pass/pointers.rs2
-rw-r--r--src/tools/miri/tests/pass/provenance.rs2
-rw-r--r--src/tools/miri/tests/pass/ptr_int_casts.rs2
-rw-r--r--src/tools/miri/tests/pass/ptr_int_from_exposed.rs2
-rw-r--r--src/tools/miri/tests/pass/ptr_int_transmute.rs2
-rw-r--r--src/tools/miri/tests/pass/rc.rs2
-rw-r--r--src/tools/miri/tests/pass/send-is-not-static-par-for.rs2
-rw-r--r--src/tools/miri/tests/pass/slices.rs2
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs6
-rw-r--r--src/tools/miri/tests/pass/threadleak_ignored.rs2
-rw-r--r--src/tools/miri/tests/pass/threadleak_ignored.stack.stderr (renamed from src/tools/miri/tests/pass/threadleak_ignored.stderr)0
-rw-r--r--src/tools/miri/tests/pass/threadleak_ignored.tree.stderr1
-rw-r--r--src/tools/miri/tests/pass/transmute_ptr.rs2
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/2phase-interiormut.rs27
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.rs27
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.stderr10
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/copy-nonoverlapping.rs29
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/end-of-protector.rs32
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/end-of-protector.stderr32
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/formatting.rs73
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/formatting.stderr29
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/read-only-from-mut.rs14
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.rs24
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.stderr13
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/reserved.rs127
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/reserved.stderr52
-rw-r--r--src/tools/miri/tests/pass/tree-borrows/transmute-unsafecell.rs13
-rw-r--r--src/tools/miri/tests/pass/unsized.rs2
-rw-r--r--src/tools/miri/tests/pass/vec.rs2
-rw-r--r--src/tools/miri/tests/pass/vecdeque.rs2
-rw-r--r--src/tools/miri/tests/pass/vecdeque.stack.stdout (renamed from src/tools/miri/tests/pass/vecdeque.stdout)0
-rw-r--r--src/tools/miri/tests/pass/vecdeque.tree.stdout2
-rw-r--r--src/tools/miri/tests/utils/macros.rs61
-rw-r--r--src/tools/miri/tests/utils/miri_extern.rs142
-rw-r--r--src/tools/miri/tests/utils/mod.rs2
-rw-r--r--src/tools/rust-analyzer/Cargo.lock16
-rw-r--r--src/tools/rust-analyzer/bench_data/numerous_macro_rules4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/adt.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/test_db.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/visibility.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs56
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs51
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/eager.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs64
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs73
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs37
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs92
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs32
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs60
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs71
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/db.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs35
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs40
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs62
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs26
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs60
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs77
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs381
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs46
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs263
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs15
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs5
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs6
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs6
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs224
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs20
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs36
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs40
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs19
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs41
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs43
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs6
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs2
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json16
-rw-r--r--src/tools/rust-analyzer/editors/code/src/client.ts13
-rw-r--r--src/tools/rust-analyzer/editors/code/src/commands.ts29
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts29
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts69
-rw-r--r--src/tools/rust-analyzer/editors/code/src/lsp_ext.ts1
-rw-r--r--src/tools/rust-analyzer/editors/code/src/main.ts1
-rw-r--r--src/tools/rust-analyzer/editors/code/src/rust_project.ts91
-rw-r--r--src/tools/rust-analyzer/editors/code/src/util.ts17
-rw-r--r--src/tools/rust-installer/src/combiner.rs7
-rw-r--r--src/tools/rust-installer/src/compression.rs136
-rw-r--r--src/tools/rust-installer/src/generator.rs7
-rw-r--r--src/tools/rust-installer/src/tarballer.rs8
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/tidy/src/bins.rs2
-rw-r--r--src/tools/tidy/src/debug_artifacts.rs12
-rw-r--r--src/tools/tidy/src/deps.rs1
-rw-r--r--src/tools/tidy/src/features.rs17
-rw-r--r--src/tools/tidy/src/main.rs21
-rw-r--r--src/tools/tidy/src/mir_opt_tests.rs41
-rw-r--r--src/tools/tidy/src/pal.rs1
-rw-r--r--src/tools/tidy/src/style.rs31
-rw-r--r--src/tools/tidy/src/target_specific_tests.rs100
-rw-r--r--src/tools/tidy/src/ui_tests.rs122
-rw-r--r--src/tools/tidy/src/walk.rs30
-rw-r--r--tests/codegen-units/polymorphization/auxiliary/poly-dep.rs4
-rw-r--r--tests/codegen-units/polymorphization/poly-foreign.rs11
-rw-r--r--tests/codegen/fewer-names.rs4
-rw-r--r--tests/codegen/inherit_overflow.rs2
-rw-r--r--tests/codegen/issues/issue-106369.rs15
-rw-r--r--tests/codegen/issues/issue-73258.rs38
-rw-r--r--tests/codegen/mem-replace-big-type.rs36
-rw-r--r--tests/codegen/mem-replace-direct-memcpy.rs21
-rw-r--r--tests/codegen/ptr-read-metadata.rs96
-rw-r--r--tests/codegen/var-names.rs4
-rw-r--r--tests/codegen/vec-as-ptr.rs19
-rw-r--r--tests/debuginfo/type-names.rs1
-rw-r--r--tests/incremental/auxiliary/circular-dependencies-aux.rs10
-rw-r--r--tests/incremental/circular-dependencies.rs37
-rw-r--r--tests/incremental/hashes/let_expressions.rs4
-rw-r--r--tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir4
-rw-r--r--tests/mir-opt/building/custom/aggregate_exprs.adt.built.after.mir16
-rw-r--r--tests/mir-opt/building/custom/aggregate_exprs.array.built.after.mir15
-rw-r--r--tests/mir-opt/building/custom/aggregate_exprs.rs71
-rw-r--r--tests/mir-opt/building/custom/aggregate_exprs.tuple.built.after.mir10
-rw-r--r--tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff1
-rw-r--r--tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff10
-rw-r--r--tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff76
-rw-r--r--tests/mir-opt/const_prop/invalid_constant.rs1
-rw-r--r--tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff7
-rw-r--r--tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff2
-rw-r--r--tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff2
-rw-r--r--tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff2
-rw-r--r--tests/mir-opt/inline/asm_unwind.main.Inline.diff16
-rw-r--r--tests/mir-opt/inline/cycle.g.Inline.diff9
-rw-r--r--tests/mir-opt/inline/cycle.main.Inline.diff9
-rw-r--r--tests/mir-opt/inline/exponential_runtime.main.Inline.diff56
-rw-r--r--tests/mir-opt/inline/inline_cycle.two.Inline.diff9
-rw-r--r--tests/mir-opt/inline/inline_diverging.g.Inline.diff2
-rw-r--r--tests/mir-opt/inline/inline_diverging.h.Inline.diff36
-rw-r--r--tests/mir-opt/inline/inline_options.main.Inline.after.mir32
-rw-r--r--tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir7
-rw-r--r--tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff12
-rw-r--r--tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff12
-rw-r--r--tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff12
-rw-r--r--tests/mir-opt/issue_101973.inner.ConstProp.diff58
-rw-r--r--tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff1
-rw-r--r--tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir1
-rw-r--r--tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff54
-rw-r--r--tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff27
-rw-r--r--tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff21
-rw-r--r--tests/mir-opt/lower_intrinsics.rs21
-rw-r--r--tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir2
-rw-r--r--tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir11
-rw-r--r--tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff4
-rw-r--r--tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff4
-rw-r--r--tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff4
-rw-r--r--tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff4
-rw-r--r--tests/mir-opt/remove_zsts.get_union.PreCodegen.after.mir5
-rw-r--r--tests/mir-opt/remove_zsts.get_union.RemoveZsts.diff9
-rw-r--r--tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff8
-rw-r--r--tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir37
-rw-r--r--tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff2
-rw-r--r--tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir80
-rw-r--r--tests/pretty/issue-4264.pp10
-rw-r--r--tests/pretty/tests-are-sorted.pp22
-rw-r--r--tests/pretty/tests-are-sorted.rs3
-rw-r--r--tests/run-make-fulldeps/tools.mk4
-rw-r--r--tests/rustdoc-js-std/option-type-signatures.js23
-rw-r--r--tests/rustdoc-js/search-bag-semantics.js20
-rw-r--r--tests/rustdoc-js/search-bag-semantics.rs4
-rw-r--r--tests/rustdoc-js/where-clause.js13
-rw-r--r--tests/rustdoc-js/where-clause.rs14
-rw-r--r--tests/rustdoc-json/fns/extern_c_variadic.rs9
-rw-r--r--tests/rustdoc-ui/intra-doc/import-inline-merge.rs16
-rw-r--r--tests/rustdoc-ui/z-help.stdout1
-rw-r--r--tests/rustdoc/deprecated.rs4
-rw-r--r--tests/rustdoc/footnote-in-summary.rs17
-rw-r--r--tests/rustdoc/intra-doc/prim-methods.rs2
-rw-r--r--tests/rustdoc/issue-109258-missing-private-inlining.rs27
-rw-r--r--tests/ui/associated-consts/issue-93775.rs2
-rw-r--r--tests/ui/async-await/async-trait-fn.current.stderr42
-rw-r--r--tests/ui/async-await/async-trait-fn.next.stderr42
-rw-r--r--tests/ui/async-await/async-trait-fn.rs1
-rw-r--r--tests/ui/async-await/async-trait-fn.stderr6
-rw-r--r--tests/ui/async-await/edition-deny-async-fns-2015.current.stderr (renamed from tests/ui/async-await/edition-deny-async-fns-2015.stderr)20
-rw-r--r--tests/ui/async-await/edition-deny-async-fns-2015.next.stderr98
-rw-r--r--tests/ui/async-await/edition-deny-async-fns-2015.rs2
-rw-r--r--tests/ui/async-await/generator-desc.stderr14
-rw-r--r--tests/ui/async-await/in-trait/async-associated-types.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-associated-types2.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-default-fn-overridden.current.stderr (renamed from tests/ui/async-await/in-trait/async-default-fn-overridden.stderr)2
-rw-r--r--tests/ui/async-await/in-trait/async-default-fn-overridden.next.stderr11
-rw-r--r--tests/ui/async-await/in-trait/async-default-fn-overridden.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.current.stderr (renamed from tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr)4
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.next.stderr17
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-boxed.current.stderr (renamed from tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr)2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-boxed.next.stderr11
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-boxed.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-extra.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-manual.current.stderr (renamed from tests/ui/async-await/in-trait/async-example-desugared-manual.stderr)2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-manual.next.stderr11
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-manual.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-generics-and-bounds.current.stderr (renamed from tests/ui/async-await/in-trait/async-generics-and-bounds.stderr)12
-rw-r--r--tests/ui/async-await/in-trait/async-generics-and-bounds.next.stderr37
-rw-r--r--tests/ui/async-await/in-trait/async-generics-and-bounds.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-generics.current.stderr (renamed from tests/ui/async-await/in-trait/async-generics.stderr)12
-rw-r--r--tests/ui/async-await/in-trait/async-generics.next.stderr37
-rw-r--r--tests/ui/async-await/in-trait/async-generics.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-recursive-generic.current.stderr (renamed from tests/ui/async-await/in-trait/async-recursive-generic.stderr)2
-rw-r--r--tests/ui/async-await/in-trait/async-recursive-generic.next.stderr12
-rw-r--r--tests/ui/async-await/in-trait/async-recursive-generic.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-recursive.current.stderr (renamed from tests/ui/async-await/in-trait/async-recursive.stderr)2
-rw-r--r--tests/ui/async-await/in-trait/async-recursive.next.stderr12
-rw-r--r--tests/ui/async-await/in-trait/async-recursive.rs2
-rw-r--r--tests/ui/async-await/in-trait/bad-signatures.current.stderr (renamed from tests/ui/async-await/in-trait/bad-signatures.stderr)6
-rw-r--r--tests/ui/async-await/in-trait/bad-signatures.next.stderr26
-rw-r--r--tests/ui/async-await/in-trait/bad-signatures.rs2
-rw-r--r--tests/ui/async-await/in-trait/early-bound-1.rs2
-rw-r--r--tests/ui/async-await/in-trait/early-bound-2.rs2
-rw-r--r--tests/ui/async-await/in-trait/fn-not-async-err2.current.stderr (renamed from tests/ui/async-await/in-trait/fn-not-async-err2.stderr)2
-rw-r--r--tests/ui/async-await/in-trait/fn-not-async-err2.next.stderr12
-rw-r--r--tests/ui/async-await/in-trait/fn-not-async-err2.rs2
-rw-r--r--tests/ui/async-await/in-trait/generics-mismatch.current.stderr16
-rw-r--r--tests/ui/async-await/in-trait/generics-mismatch.next.stderr16
-rw-r--r--tests/ui/async-await/in-trait/generics-mismatch.rs15
-rw-r--r--tests/ui/async-await/in-trait/generics-mismatch.stderr16
-rw-r--r--tests/ui/async-await/in-trait/implied-bounds.rs2
-rw-r--r--tests/ui/async-await/in-trait/issue-102138.rs2
-rw-r--r--tests/ui/async-await/in-trait/issue-102219.rs2
-rw-r--r--tests/ui/async-await/in-trait/issue-102310.rs2
-rw-r--r--tests/ui/async-await/in-trait/lifetime-mismatch.current.stderr (renamed from tests/ui/async-await/in-trait/lifetime-mismatch.stderr)4
-rw-r--r--tests/ui/async-await/in-trait/lifetime-mismatch.next.stderr21
-rw-r--r--tests/ui/async-await/in-trait/lifetime-mismatch.rs2
-rw-r--r--tests/ui/async-await/in-trait/missing-send-bound.current.stderr (renamed from tests/ui/async-await/in-trait/missing-send-bound.stderr)8
-rw-r--r--tests/ui/async-await/in-trait/missing-send-bound.next.stderr29
-rw-r--r--tests/ui/async-await/in-trait/missing-send-bound.rs2
-rw-r--r--tests/ui/async-await/in-trait/object-safety.current.stderr (renamed from tests/ui/async-await/in-trait/object-safety.stderr)6
-rw-r--r--tests/ui/async-await/in-trait/object-safety.next.stderr27
-rw-r--r--tests/ui/async-await/in-trait/object-safety.rs2
-rw-r--r--tests/ui/async-await/in-trait/return-type-suggestion.current.stderr (renamed from tests/ui/async-await/in-trait/return-type-suggestion.stderr)4
-rw-r--r--tests/ui/async-await/in-trait/return-type-suggestion.next.stderr23
-rw-r--r--tests/ui/async-await/in-trait/return-type-suggestion.rs2
-rw-r--r--tests/ui/async-await/large_moves.attribute.stderr22
-rw-r--r--tests/ui/async-await/large_moves.option.stderr22
-rw-r--r--tests/ui/async-await/large_moves.rs2
-rw-r--r--tests/ui/async-await/no-const-async.rs1
-rw-r--r--tests/ui/async-await/no-const-async.stderr33
-rw-r--r--tests/ui/async-await/track-caller/async-block.rs4
-rw-r--r--tests/ui/async-await/track-caller/async-block.stderr14
-rw-r--r--tests/ui/async-await/track-caller/panic-track-caller.rs13
-rw-r--r--tests/ui/borrowck/issue-64453.stderr2
-rw-r--r--tests/ui/chalkify/bugs/async.rs2
-rw-r--r--tests/ui/chalkify/bugs/async.stderr34
-rw-r--r--tests/ui/codegen/mono-impossible.rs13
-rw-r--r--tests/ui/conditional-compilation/cfg-attr-multi-true.stderr4
-rw-r--r--tests/ui/const-generics/bad-subst-const-kind.rs13
-rw-r--r--tests/ui/const-generics/bad-subst-const-kind.stderr9
-rw-r--r--tests/ui/const-generics/const-arg-in-const-arg.full.stderr17
-rw-r--r--tests/ui/const-generics/const-arg-in-const-arg.min.stderr18
-rw-r--r--tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.rs11
-rw-r--r--tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.stderr18
-rw-r--r--tests/ui/const-ptr/out_of_bounds_read.stderr6
-rw-r--r--tests/ui/consts/const-eval/format.rs3
-rw-r--r--tests/ui/consts/const-eval/format.stderr29
-rw-r--r--tests/ui/consts/const-eval/ub-ref-ptr.stderr24
-rw-r--r--tests/ui/consts/issue-miri-1910.stderr2
-rw-r--r--tests/ui/consts/offset_from_ub.stderr6
-rw-r--r--tests/ui/did_you_mean/recursion_limit.stderr7
-rw-r--r--tests/ui/error-codes/E0275.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-closure_track_caller.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-closure_track_caller.stderr15
-rw-r--r--tests/ui/fmt/auxiliary/format-string-proc-macro.rs36
-rw-r--r--tests/ui/fmt/format-args-capture-first-literal-is-macro.rs21
-rw-r--r--tests/ui/fmt/format-args-capture-first-literal-is-macro.stderr30
-rw-r--r--tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.rs8
-rw-r--r--tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.stderr12
-rw-r--r--tests/ui/fmt/format-args-capture-issue-106408.rs10
-rw-r--r--tests/ui/fmt/format-args-capture-macro-hygiene-pass.rs16
-rw-r--r--tests/ui/fmt/respanned-literal-issue-106191.rs9
-rw-r--r--tests/ui/fmt/respanned-literal-issue-106191.stderr21
-rw-r--r--tests/ui/impl-trait/in-trait/box-coerce-span-in-default.current.stderr (renamed from tests/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr)2
-rw-r--r--tests/ui/impl-trait/in-trait/box-coerce-span-in-default.next.stderr (renamed from tests/ui/impl-trait/in-trait/default-method-binder-shifting.stderr)2
-rw-r--r--tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/deep-match-works.rs6
-rw-r--r--tests/ui/impl-trait/in-trait/deep-match.current.stderr (renamed from tests/ui/impl-trait/in-trait/deep-match.stderr)4
-rw-r--r--tests/ui/impl-trait/in-trait/deep-match.next.stderr15
-rw-r--r--tests/ui/impl-trait/in-trait/deep-match.rs9
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-type-err-2.current.stderr (renamed from tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr)2
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-type-err-2.next.stderr11
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-type-err-2.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-type-err.current.stderr (renamed from tests/ui/impl-trait/in-trait/default-body-type-err.stderr)2
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-type-err.next.stderr12
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-type-err.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-with-rpit.current.stderr24
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr24
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-with-rpit.rs4
-rw-r--r--tests/ui/impl-trait/in-trait/default-body.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/default-method-binder-shifting.current.stderr11
-rw-r--r--tests/ui/impl-trait/in-trait/default-method-binder-shifting.next.stderr11
-rw-r--r--tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs8
-rw-r--r--tests/ui/impl-trait/in-trait/default-method-constraint.current.stderr (renamed from tests/ui/impl-trait/in-trait/default-method-constraint.stderr)2
-rw-r--r--tests/ui/impl-trait/in-trait/default-method-constraint.next.stderr11
-rw-r--r--tests/ui/impl-trait/in-trait/default-method-constraint.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/doesnt-satisfy.current.stderr (renamed from tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr)4
-rw-r--r--tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr17
-rw-r--r--tests/ui/impl-trait/in-trait/doesnt-satisfy.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/early.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/encode.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/foreign.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/generics-mismatch.current.stderr (renamed from tests/ui/impl-trait/in-trait/generics-mismatch.stderr)2
-rw-r--r--tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr12
-rw-r--r--tests/ui/impl-trait/in-trait/generics-mismatch.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102140.current.stderr (renamed from tests/ui/impl-trait/in-trait/issue-102140.stderr)6
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102140.next.stderr33
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102140.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102301.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102571.current.stderr (renamed from tests/ui/impl-trait/in-trait/issue-102571.stderr)2
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102571.next.stderr14
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102571.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/new-lowering-strategy/simple-impl-trait.rs17
-rw-r--r--tests/ui/impl-trait/in-trait/new-lowering-strategy/simple-trait.rs11
-rw-r--r--tests/ui/impl-trait/in-trait/object-safety.current.stderr (renamed from tests/ui/impl-trait/in-trait/object-safety.stderr)12
-rw-r--r--tests/ui/impl-trait/in-trait/object-safety.next.stderr50
-rw-r--r--tests/ui/impl-trait/in-trait/object-safety.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.current.stderr (renamed from tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr)2
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.next.stderr17
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-in-impl.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/reveal.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/signature-mismatch.current.stderr (renamed from tests/ui/impl-trait/in-trait/signature-mismatch.stderr)2
-rw-r--r--tests/ui/impl-trait/in-trait/signature-mismatch.next.stderr16
-rw-r--r--tests/ui/impl-trait/in-trait/signature-mismatch.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/specialization-broken.current.stderr (renamed from tests/ui/impl-trait/in-trait/specialization-broken.stderr)6
-rw-r--r--tests/ui/impl-trait/in-trait/specialization-broken.next.stderr31
-rw-r--r--tests/ui/impl-trait/in-trait/specialization-broken.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/specialization-substs-remap.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/success.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.current.stderr (renamed from tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr)2
-rw-r--r--tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.next.stderr12
-rw-r--r--tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/wf-bounds.current.stderr (renamed from tests/ui/impl-trait/in-trait/wf-bounds.stderr)6
-rw-r--r--tests/ui/impl-trait/in-trait/wf-bounds.next.stderr30
-rw-r--r--tests/ui/impl-trait/in-trait/wf-bounds.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/where-clause.rs2
-rw-r--r--tests/ui/impl-trait/issues/issue-78722.rs1
-rw-r--r--tests/ui/impl-trait/issues/issue-78722.stderr13
-rw-r--r--tests/ui/imports/issue-99695-b.fixed2
-rw-r--r--tests/ui/imports/issue-99695-b.rs2
-rw-r--r--tests/ui/imports/issue-99695.fixed2
-rw-r--r--tests/ui/imports/issue-99695.rs2
-rw-r--r--tests/ui/issues/issue-19086.stderr2
-rw-r--r--tests/ui/issues/issue-20413.stderr34
-rw-r--r--tests/ui/late-bound-lifetimes/issue-80618.rs8
-rw-r--r--tests/ui/late-bound-lifetimes/issue-80618.stderr15
-rw-r--r--tests/ui/layout/transmute-to-tail-with-err.rs8
-rw-r--r--tests/ui/layout/transmute-to-tail-with-err.stderr14
-rw-r--r--tests/ui/lifetimes/unusual-rib-combinations.rs5
-rw-r--r--tests/ui/lifetimes/unusual-rib-combinations.stderr21
-rw-r--r--tests/ui/linkage-attr/issue-109144.rs4
-rw-r--r--tests/ui/linkage-attr/issue-109144.stderr9
-rw-r--r--tests/ui/lint/anonymous-reexport.rs21
-rw-r--r--tests/ui/lint/anonymous-reexport.stderr55
-rw-r--r--tests/ui/lint/clashing-extern-fn.rs33
-rw-r--r--tests/ui/lint/clashing-extern-fn.stderr18
-rw-r--r--tests/ui/lint/fn_must_use.stderr28
-rw-r--r--tests/ui/lint/issue-109152.rs7
-rw-r--r--tests/ui/lint/issue-109152.stderr23
-rw-r--r--tests/ui/lint/unused/must-use-box-from-raw.stderr4
-rw-r--r--tests/ui/lint/unused/must_use-unit.stderr9
-rw-r--r--tests/ui/lint/unused/unused-async.stderr20
-rw-r--r--tests/ui/lint/unused/unused-result.stderr17
-rw-r--r--tests/ui/lint/unused/unused_attributes-must_use.stderr34
-rw-r--r--tests/ui/macros/issue-109237.rs7
-rw-r--r--tests/ui/macros/issue-109237.stderr18
-rw-r--r--tests/ui/macros/nested-use-as.rs83
-rw-r--r--tests/ui/methods/method-call-lifetime-args-fail.stderr31
-rw-r--r--tests/ui/methods/method-call-lifetime-args.stderr5
-rw-r--r--tests/ui/panic-runtime/unwind-tables-target-required.rs5
-rw-r--r--tests/ui/parser/fn-header-semantic-fail.rs3
-rw-r--r--tests/ui/parser/fn-header-semantic-fail.stderr146
-rw-r--r--tests/ui/pattern/issue-106862.fixed44
-rw-r--r--tests/ui/pattern/issue-106862.rs44
-rw-r--r--tests/ui/pattern/issue-106862.stderr48
-rw-r--r--tests/ui/proc-macro/bad-projection.rs15
-rw-r--r--tests/ui/proc-macro/bad-projection.stderr9
-rw-r--r--tests/ui/proc-macro/proc-macro-abi.rs6
-rw-r--r--tests/ui/proc-macro/proc-macro-abi.stderr21
-rw-r--r--tests/ui/proc-macro/signature-proc-macro-attribute.rs10
-rw-r--r--tests/ui/proc-macro/signature-proc-macro-attribute.stderr46
-rw-r--r--tests/ui/proc-macro/signature-proc-macro-derive.rs9
-rw-r--r--tests/ui/proc-macro/signature-proc-macro-derive.stderr40
-rw-r--r--tests/ui/proc-macro/signature-proc-macro.rs9
-rw-r--r--tests/ui/proc-macro/signature-proc-macro.stderr40
-rw-r--r--tests/ui/proc-macro/signature.rs6
-rw-r--r--tests/ui/proc-macro/signature.stderr35
-rw-r--r--tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs5
-rw-r--r--tests/ui/rfc-2091-track-caller/mir-inlined-macro.rs23
-rw-r--r--tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs4
-rw-r--r--tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr15
-rw-r--r--tests/ui/stability-attribute/auxiliary/similar-unstable-method.rs13
-rw-r--r--tests/ui/stability-attribute/issue-109177.rs13
-rw-r--r--tests/ui/stability-attribute/issue-109177.stderr21
-rw-r--r--tests/ui/suggestions/bad-infer-in-trait-impl.rs10
-rw-r--r--tests/ui/suggestions/bad-infer-in-trait-impl.stderr14
-rw-r--r--tests/ui/suggestions/chain-method-call-mutation-in-place.rs6
-rw-r--r--tests/ui/suggestions/chain-method-call-mutation-in-place.stderr37
-rw-r--r--tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr11
-rw-r--r--tests/ui/suggestions/issue-109396.rs12
-rw-r--r--tests/ui/suggestions/issue-109396.stderr34
-rw-r--r--tests/ui/suggestions/suggest-ret-on-async-w-late.rs11
-rw-r--r--tests/ui/suggestions/suggest-ret-on-async-w-late.stderr11
-rw-r--r--tests/ui/test-attrs/custom-test-frameworks/issue-107454.rs10
-rw-r--r--tests/ui/test-attrs/custom-test-frameworks/issue-107454.stderr15
-rw-r--r--tests/ui/test-attrs/tests-listing-format-default.rs18
-rw-r--r--tests/ui/test-attrs/tests-listing-format-default.run.stdout5
-rw-r--r--tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs18
-rw-r--r--tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr1
-rw-r--r--tests/ui/test-attrs/tests-listing-format-json.rs20
-rw-r--r--tests/ui/test-attrs/tests-listing-format-json.run.stdout5
-rw-r--r--tests/ui/test-attrs/tests-listing-format-terse.rs18
-rw-r--r--tests/ui/test-attrs/tests-listing-format-terse.run.stdout3
-rw-r--r--tests/ui/traits/cycle-cache-err-60010.stderr15
-rw-r--r--tests/ui/traits/issue-91949-hangs-on-recursion.rs2
-rw-r--r--tests/ui/traits/issue-91949-hangs-on-recursion.stderr12
-rw-r--r--tests/ui/traits/new-solver/fn-trait.rs21
-rw-r--r--tests/ui/traits/new-solver/fn-trait.stderr124
-rw-r--r--tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.rs11
-rw-r--r--tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.stderr19
-rw-r--r--tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs11
-rw-r--r--tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr18
-rw-r--r--tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs24
-rw-r--r--tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr56
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_item.rs1
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_item.stderr15
-rw-r--r--tests/ui/unpretty/flattened-format-args.rs8
-rw-r--r--tests/ui/unpretty/flattened-format-args.stdout16
-rw-r--r--triagebot.toml1
1065 files changed, 18340 insertions, 8027 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3873a020b75..b45246eb4ea 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -48,19 +48,19 @@ jobs:
         include:
           - name: mingw-check
             tidy: false
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: mingw-check-tidy
             tidy: true
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: x86_64-gnu-llvm-14
             tidy: false
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: x86_64-gnu-tools
             tidy: false
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
     timeout-minutes: 600
     runs-on: "${{ matrix.os }}"
@@ -181,136 +181,136 @@ jobs:
               - ARM64
               - linux
           - name: arm-android
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: armhf-gnu
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-aarch64-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-android
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-arm-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-armhf-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-armv7-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-i586-gnu-i586-i686-musl
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-i686-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-mips-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-mips64-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-mips64el-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-mipsel-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-powerpc-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-powerpc64-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-powerpc64le-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-riscv64-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-s390x-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-various-1
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-various-2
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-x86_64-freebsd
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-x86_64-illumos
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-x86_64-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-x86_64-linux-alt
             env:
               IMAGE: dist-x86_64-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
           - name: dist-x86_64-musl
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: dist-x86_64-netbsd
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: i686-gnu
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: i686-gnu-nopt
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: mingw-check
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: test-various
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: wasm32
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: x86_64-gnu
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: x86_64-gnu-stable
             env:
               IMAGE: x86_64-gnu
               RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable
               CI_ONLY_WHEN_CHANNEL: nightly
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
           - name: x86_64-gnu-aux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: x86_64-gnu-debug
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: x86_64-gnu-distcheck
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: x86_64-gnu-llvm-15
             env:
               RUST_BACKTRACE: 1
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
           - name: x86_64-gnu-llvm-14
             env:
               RUST_BACKTRACE: 1
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
           - name: x86_64-gnu-llvm-14-stage1
             env:
               RUST_BACKTRACE: 1
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
           - name: x86_64-gnu-nopt
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
           - name: x86_64-gnu-tools
             env:
               DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
           - name: dist-x86_64-apple
             env:
               SCRIPT: "./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin"
@@ -386,80 +386,80 @@ jobs:
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
               SCRIPT: make ci-subset-1
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: x86_64-msvc-2
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
               SCRIPT: make ci-subset-2
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: i686-msvc-1
             env:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc"
               SCRIPT: make ci-subset-1
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: i686-msvc-2
             env:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc"
               SCRIPT: make ci-subset-2
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: x86_64-msvc-cargo
             env:
               SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-lld"
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: x86_64-msvc-tools
             env:
               SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json"
               DEPLOY_TOOLSTATES_JSON: toolstates-windows.json
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: i686-mingw-1
             env:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
               SCRIPT: make ci-mingw-subset-1
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: i686-mingw-2
             env:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
               SCRIPT: make ci-mingw-subset-2
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: x86_64-mingw-1
             env:
               SCRIPT: make ci-mingw-subset-1
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: x86_64-mingw-2
             env:
               SCRIPT: make ci-mingw-subset-2
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: dist-x86_64-msvc
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler"
               SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: dist-i686-msvc
             env:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler"
               SCRIPT: python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: dist-aarch64-msvc
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=aarch64-pc-windows-msvc --enable-full-tools --enable-profiler"
               SCRIPT: python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
               WINDOWS_SDK_20348_HACK: 1
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: dist-i686-mingw
             env:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler"
@@ -467,7 +467,7 @@ jobs:
               SCRIPT: python x.py dist bootstrap --include-default-paths
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: dist-x86_64-mingw
             env:
               SCRIPT: python x.py dist bootstrap --include-default-paths
@@ -475,12 +475,12 @@ jobs:
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
           - name: dist-x86_64-msvc-alt
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-extended --enable-profiler"
               SCRIPT: python x.py dist bootstrap --include-default-paths
-            os: windows-latest-xl
+            os: windows-2019-8core-32gb
     timeout-minutes: 600
     runs-on: "${{ matrix.os }}"
     steps:
@@ -595,7 +595,7 @@ jobs:
       matrix:
         include:
           - name: dist-x86_64-linux
-            os: ubuntu-20.04-xl
+            os: ubuntu-20.04-16core-64gb
             env: {}
     timeout-minutes: 600
     runs-on: "${{ matrix.os }}"
diff --git a/.gitignore b/.gitignore
index ce797a7a837..485968d9c56 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@ Session.vim
 .project
 .favorites.json
 .settings/
+.vs/
 
 ## Tool
 .valgrindrc
@@ -42,6 +43,7 @@ no_llvm_build
 /llvm/
 /mingw-build/
 build/
+!/compiler/rustc_mir_build/src/build/
 /build-rust-analyzer/
 /dist/
 /unicode-downloads
diff --git a/.mailmap b/.mailmap
index 715bc4d3085..9148b79e980 100644
--- a/.mailmap
+++ b/.mailmap
@@ -29,6 +29,8 @@ Alexander Ronald Altman <alexanderaltman@me.com>
 Alexandre Martin <martin.alex32@hotmail.fr>
 Alexis Beingessner <a.beingessner@gmail.com>
 Alfie John <alfie@alfie.wtf> Alfie John <alfiej@fastmail.fm>
+Alona Enraght-Moony <code@alona.page> <nixon.emoony@gmail.com>
+Alona Enraght-Moony <code@alona.page> <nixon@caminus.local>
 Amos Onn <amosonn@gmail.com>
 Ana-Maria Mihalache <mihalacheana.maria@yahoo.com>
 Anatoly Ikorsky <aikorsky@gmail.com>
@@ -415,7 +417,6 @@ Nicolas Abram <abramlujan@gmail.com>
 Nicole Mazzuca <npmazzuca@gmail.com>
 Nif Ward <nif.ward@gmail.com>
 Nika Layzell <nika@thelayzells.com> <michael@thelayzells.com>
-Nixon Enraght-Moony <nixon.emoony@gmail.com>
 NODA Kai <nodakai@gmail.com>
 oliver <16816606+o752d@users.noreply.github.com>
 Oliver Middleton <olliemail27@gmail.com> <ollie27@users.noreply.github.com>
diff --git a/Cargo.lock b/Cargo.lock
index 51332919fe7..2b08aab41ed 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -353,7 +353,7 @@ dependencies = [
 
 [[package]]
 name = "cargo"
-version = "0.70.0"
+version = "0.71.0"
 dependencies = [
  "anyhow",
  "base64",
@@ -898,7 +898,7 @@ dependencies = [
  "tracing-subscriber",
  "unified-diff",
  "walkdir",
- "winapi",
+ "windows 0.46.0",
 ]
 
 [[package]]
@@ -1001,7 +1001,7 @@ dependencies = [
 
 [[package]]
 name = "crates-io"
-version = "0.35.1"
+version = "0.36.0"
 dependencies = [
  "anyhow",
  "curl",
@@ -1128,9 +1128,9 @@ dependencies = [
 
 [[package]]
 name = "curl-sys"
-version = "0.4.59+curl-7.86.0"
+version = "0.4.61+curl-8.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6cfce34829f448b08f55b7db6d0009e23e2e86a34e8c2b366269bf5799b4a407"
+checksum = "14d05c10f541ae6f3bc5b3d923c20001f47db7d5f0b2bc6ad16490133842db79"
 dependencies = [
  "cc",
  "libc",
@@ -1365,9 +1365,9 @@ dependencies = [
 
 [[package]]
 name = "ena"
-version = "0.14.1"
+version = "0.14.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2e5d13ca2353ab7d0230988629def93914a8c4015f621f9b13ed2955614731d"
+checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
 dependencies = [
  "log",
 ]
@@ -2273,7 +2273,7 @@ dependencies = [
  "dirs",
  "gix-path",
  "libc",
- "windows",
+ "windows 0.43.0",
 ]
 
 [[package]]
@@ -3103,9 +3103,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.25"
+version = "0.4.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1ed28d5903dde77bd5182645078a37ee57014cac6ccb2d54e1d6496386648e4"
+checksum = "764dcbfc2e5f868bc1b566eb179dff1a06458fd0cff846aae2579392dd3f01a0"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -4529,7 +4529,7 @@ dependencies = [
  "tempfile",
  "thin-vec",
  "tracing",
- "winapi",
+ "windows 0.46.0",
 ]
 
 [[package]]
@@ -4588,7 +4588,7 @@ dependencies = [
  "rustc_ty_utils",
  "serde_json",
  "tracing",
- "winapi",
+ "windows 0.46.0",
 ]
 
 [[package]]
@@ -4636,7 +4636,7 @@ dependencies = [
  "termize",
  "tracing",
  "unicode-width",
- "winapi",
+ "windows 0.46.0",
 ]
 
 [[package]]
@@ -5139,6 +5139,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
+ "rustc_trait_selection",
  "tracing",
 ]
 
@@ -5276,7 +5277,7 @@ dependencies = [
  "smallvec",
  "termize",
  "tracing",
- "winapi",
+ "windows 0.46.0",
 ]
 
 [[package]]
@@ -5457,13 +5458,13 @@ dependencies = [
  "itertools",
  "minifier",
  "once_cell",
- "rayon",
  "regex",
  "rustdoc-json-types",
  "serde",
  "serde_json",
  "smallvec",
  "tempfile",
+ "threadpool",
  "tracing",
  "tracing-subscriber",
  "tracing-tree",
@@ -6209,6 +6210,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "threadpool"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
+dependencies = [
+ "num_cpus",
+]
+
+[[package]]
 name = "tidy"
 version = "0.1.0"
 dependencies = [
@@ -6899,6 +6909,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
 name = "windows-sys"
 version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6924,9 +6943,9 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
 dependencies = [
  "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
@@ -6939,45 +6958,45 @@ dependencies = [
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
 
 [[package]]
 name = "writeable"
diff --git a/RELEASES.md b/RELEASES.md
index 4e974bbe974..a26dbbfa4f5 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -125,12 +125,13 @@ Compiler
 - [Optimize field ordering by grouping m\*2^n-sized fields with equivalently aligned ones.](https://github.com/rust-lang/rust/pull/102750/)
 - [Stabilize native library modifier `verbatim`.](https://github.com/rust-lang/rust/pull/104360/)
 
-Added and removed targets:
+Added, updated, and removed targets:
 
 - [Add a tier 3 target for PowerPC on AIX](https://github.com/rust-lang/rust/pull/102293/), `powerpc64-ibm-aix`.
 - [Add a tier 3 target for the Sony PlayStation 1](https://github.com/rust-lang/rust/pull/102689/), `mipsel-sony-psx`.
 - [Add tier 3 `no_std` targets for the QNX Neutrino RTOS](https://github.com/rust-lang/rust/pull/102701/),
   `aarch64-unknown-nto-qnx710` and `x86_64-pc-nto-qnx710`.
+- [Promote UEFI targets to tier 2](https://github.com/rust-lang/rust/pull/103933/), `aarch64-unknown-uefi`, `i686-unknown-uefi`, and `x86_64-unknown-uefi`.
 - [Remove tier 3 `linuxkernel` targets](https://github.com/rust-lang/rust/pull/104015/) (not used by the actual kernel).
 
 Refer to Rust's [platform support page][platform-support-doc]
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 6503bf2bab7..5d164bc4b3c 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1184,6 +1184,15 @@ impl Expr {
         expr
     }
 
+    pub fn peel_parens_and_refs(&self) -> &Expr {
+        let mut expr = self;
+        while let ExprKind::Paren(inner) | ExprKind::AddrOf(BorrowKind::Ref, _, inner) = &expr.kind
+        {
+            expr = inner;
+        }
+        expr
+    }
+
     /// Attempts to reparse as `Ty` (for diagnostic purposes).
     pub fn to_ty(&self) -> Option<P<Ty>> {
         let kind = match &self.kind {
diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs
index d021bea5eca..356b9bb6371 100644
--- a/compiler/rustc_ast/src/format.rs
+++ b/compiler/rustc_ast/src/format.rs
@@ -131,8 +131,8 @@ impl FormatArguments {
         &self.arguments[..]
     }
 
-    pub fn all_args_mut(&mut self) -> &mut [FormatArgument] {
-        &mut self.arguments[..]
+    pub fn all_args_mut(&mut self) -> &mut Vec<FormatArgument> {
+        &mut self.arguments
     }
 }
 
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 3a0af04f9eb..3893875e9a4 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -259,7 +259,6 @@ pub enum ExprPrecedence {
     Assign,
     AssignOp,
 
-    Box,
     AddrOf,
     Let,
     Unary,
@@ -319,8 +318,7 @@ impl ExprPrecedence {
             ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
 
             // Unary, prefix
-            ExprPrecedence::Box
-            | ExprPrecedence::AddrOf
+            ExprPrecedence::AddrOf
             // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
             // However, this is not exactly right. When `let _ = a` is the LHS of a binop we
             // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 4390680c45a..181f94ab74f 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -32,7 +32,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
         ensure_sufficient_stack(|| {
             match &e.kind {
-                // Paranthesis expression does not have a HirId and is handled specially.
+                // Parenthesis expression does not have a HirId and is handled specially.
                 ExprKind::Paren(ex) => {
                     let mut ex = self.lower_expr_mut(ex);
                     // Include parens in span, but only if it is a super-span.
@@ -63,6 +63,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ExprKind::ForLoop(pat, head, body, opt_label) => {
                     return self.lower_expr_for(e, pat, head, body, *opt_label);
                 }
+                // Similarly, async blocks do not use `e.id` but rather `closure_node_id`.
+                ExprKind::Async(capture_clause, closure_node_id, block) => {
+                    let hir_id = self.lower_node_id(*closure_node_id);
+                    self.lower_attrs(hir_id, &e.attrs);
+                    return self.make_async_expr(
+                        *capture_clause,
+                        hir_id,
+                        *closure_node_id,
+                        None,
+                        e.span,
+                        hir::AsyncGeneratorKind::Block,
+                        |this| this.with_new_scopes(|this| this.lower_block_expr(block)),
+                    );
+                }
                 _ => (),
             }
 
@@ -173,15 +187,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
                     hir::MatchSource::Normal,
                 ),
-                ExprKind::Async(capture_clause, closure_node_id, block) => self.make_async_expr(
-                    *capture_clause,
-                    hir_id,
-                    *closure_node_id,
-                    None,
-                    e.span,
-                    hir::AsyncGeneratorKind::Block,
-                    |this| this.with_new_scopes(|this| this.lower_block_expr(block)),
-                ),
                 ExprKind::Await(expr) => {
                     let dot_await_span = if expr.span.hi() < e.span.hi() {
                         let span_with_whitespace = self
@@ -315,7 +320,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ),
                 ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
 
-                ExprKind::Paren(_) | ExprKind::ForLoop(..) => unreachable!("already handled"),
+                ExprKind::Paren(_) | ExprKind::ForLoop(..) | ExprKind::Async(..) => {
+                    unreachable!("already handled")
+                }
 
                 ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
             };
@@ -577,9 +584,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
     /// This results in:
     ///
     /// ```text
-    /// std::future::identity_future(static move? |_task_context| -> <ret_ty> {
+    /// static move? |_task_context| -> <ret_ty> {
     ///     <body>
-    /// })
+    /// }
     /// ```
     pub(super) fn make_async_expr(
         &mut self,
@@ -590,7 +597,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         span: Span,
         async_gen_kind: hir::AsyncGeneratorKind,
         body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
-    ) -> hir::ExprKind<'hir> {
+    ) -> hir::Expr<'hir> {
         let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
 
         // Resume argument type: `ResumeTy`
@@ -655,13 +662,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
         };
 
         let hir_id = self.lower_node_id(closure_node_id);
-        let unstable_span =
-            self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
-
         if self.tcx.features().closure_track_caller
             && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
             && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
         {
+            let unstable_span =
+                self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
             self.lower_attrs(
                 hir_id,
                 &[Attribute {
@@ -680,22 +686,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             );
         }
 
-        let generator = hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) };
-
-        // FIXME(swatinem):
-        // For some reason, the async block needs to flow through *any*
-        // call (like the identity function), as otherwise type and lifetime
-        // inference have a hard time figuring things out.
-        // Without this, we would get:
-        // E0720 in tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
-        // E0700 in tests/ui/self/self_lifetime-async.rs
-
-        // `future::identity_future`:
-        let identity_future =
-            self.expr_lang_item_path(unstable_span, hir::LangItem::IdentityFuture, None);
-
-        // `future::identity_future(generator)`:
-        hir::ExprKind::Call(self.arena.alloc(identity_future), arena_vec![self; generator])
+        hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) }
     }
 
     /// Desugar `<expr>.await` into:
@@ -1001,7 +992,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
 
             // Transform `async |x: u8| -> X { ... }` into
-            // `|x: u8| identity_future(|| -> X { ... })`.
+            // `|x: u8| || -> X { ... }`.
             let body_id = this.lower_fn_body(&outer_decl, |this| {
                 let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
                     let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
@@ -1010,7 +1001,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     None
                 };
 
-                let async_body = this.make_async_expr(
+                this.make_async_expr(
                     capture_clause,
                     closure_hir_id,
                     inner_closure_id,
@@ -1018,8 +1009,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     body.span,
                     hir::AsyncGeneratorKind::Closure,
                     |this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
-                );
-                this.expr(fn_decl_span, async_body)
+                )
             });
             body_id
         });
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index 4095e225a80..72352b138cb 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -7,13 +7,172 @@ use rustc_hir as hir;
 use rustc_span::{
     sym,
     symbol::{kw, Ident},
-    Span,
+    Span, Symbol,
 };
+use std::borrow::Cow;
 
 impl<'hir> LoweringContext<'_, 'hir> {
     pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
-        expand_format_args(self, sp, fmt)
+        // Never call the const constructor of `fmt::Arguments` if the
+        // format_args!() had any arguments _before_ flattening/inlining.
+        let allow_const = fmt.arguments.all_args().is_empty();
+        let mut fmt = Cow::Borrowed(fmt);
+        if self.tcx.sess.opts.unstable_opts.flatten_format_args {
+            fmt = flatten_format_args(fmt);
+            fmt = inline_literals(fmt);
+        }
+        expand_format_args(self, sp, &fmt, allow_const)
+    }
+}
+
+/// Flattens nested `format_args!()` into one.
+///
+/// Turns
+///
+/// `format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3)`
+///
+/// into
+///
+/// `format_args!("a {} b{}! {}.", 1, 2, 3)`.
+fn flatten_format_args(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> {
+    let mut i = 0;
+    while i < fmt.template.len() {
+        if let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i]
+            && let FormatTrait::Display | FormatTrait::Debug = &placeholder.format_trait
+            && let Ok(arg_index) = placeholder.argument.index
+            && let arg = fmt.arguments.all_args()[arg_index].expr.peel_parens_and_refs()
+            && let ExprKind::FormatArgs(_) = &arg.kind
+            // Check that this argument is not used by any other placeholders.
+            && fmt.template.iter().enumerate().all(|(j, p)|
+                i == j ||
+                !matches!(p, FormatArgsPiece::Placeholder(placeholder)
+                    if placeholder.argument.index == Ok(arg_index))
+            )
+        {
+            // Now we need to mutate the outer FormatArgs.
+            // If this is the first time, this clones the outer FormatArgs.
+            let fmt = fmt.to_mut();
+
+            // Take the inner FormatArgs out of the outer arguments, and
+            // replace it by the inner arguments. (We can't just put those at
+            // the end, because we need to preserve the order of evaluation.)
+
+            let args = fmt.arguments.all_args_mut();
+            let remaining_args = args.split_off(arg_index + 1);
+            let old_arg_offset = args.len();
+            let mut fmt2 = &mut args.pop().unwrap().expr; // The inner FormatArgs.
+            let fmt2 = loop { // Unwrap the Expr to get to the FormatArgs.
+                match &mut fmt2.kind {
+                    ExprKind::Paren(inner) | ExprKind::AddrOf(BorrowKind::Ref, _, inner) => fmt2 = inner,
+                    ExprKind::FormatArgs(fmt2) => break fmt2,
+                    _ => unreachable!(),
+                }
+            };
+
+            args.append(fmt2.arguments.all_args_mut());
+            let new_arg_offset = args.len();
+            args.extend(remaining_args);
+
+            // Correct the indexes that refer to the arguments after the newly inserted arguments.
+            for_all_argument_indexes(&mut fmt.template, |index| {
+                if *index >= old_arg_offset {
+                    *index -= old_arg_offset;
+                    *index += new_arg_offset;
+                }
+            });
+
+            // Now merge the placeholders:
+
+            let rest = fmt.template.split_off(i + 1);
+            fmt.template.pop(); // remove the placeholder for the nested fmt args.
+            // Insert the pieces from the nested format args, but correct any
+            // placeholders to point to the correct argument index.
+            for_all_argument_indexes(&mut fmt2.template, |index| *index += arg_index);
+            fmt.template.append(&mut fmt2.template);
+            fmt.template.extend(rest);
+
+            // Don't increment `i` here, so we recurse into the newly added pieces.
+        } else {
+            i += 1;
+        }
     }
+    fmt
+}
+
+/// Inline literals into the format string.
+///
+/// Turns
+///
+/// `format_args!("Hello, {}! {} {}", "World", 123, x)`
+///
+/// into
+///
+/// `format_args!("Hello, World! 123 {}", x)`.
+fn inline_literals(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> {
+    let mut was_inlined = vec![false; fmt.arguments.all_args().len()];
+    let mut inlined_anything = false;
+
+    for i in 0..fmt.template.len() {
+        let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i] else { continue };
+        let Ok(arg_index) = placeholder.argument.index else { continue };
+
+        let mut literal = None;
+
+        if let FormatTrait::Display = placeholder.format_trait
+            && placeholder.format_options == Default::default()
+            && let arg = fmt.arguments.all_args()[arg_index].expr.peel_parens_and_refs()
+            && let ExprKind::Lit(lit) = arg.kind
+        {
+            if let token::LitKind::Str | token::LitKind::StrRaw(_) = lit.kind
+                && let Ok(LitKind::Str(s, _)) = LitKind::from_token_lit(lit)
+            {
+                literal = Some(s);
+            } else if let token::LitKind::Integer = lit.kind
+                && let Ok(LitKind::Int(n, _)) = LitKind::from_token_lit(lit)
+            {
+                literal = Some(Symbol::intern(&n.to_string()));
+            }
+        }
+
+        if let Some(literal) = literal {
+            // Now we need to mutate the outer FormatArgs.
+            // If this is the first time, this clones the outer FormatArgs.
+            let fmt = fmt.to_mut();
+            // Replace the placeholder with the literal.
+            fmt.template[i] = FormatArgsPiece::Literal(literal);
+            was_inlined[arg_index] = true;
+            inlined_anything = true;
+        }
+    }
+
+    // Remove the arguments that were inlined.
+    if inlined_anything {
+        let fmt = fmt.to_mut();
+
+        let mut remove = was_inlined;
+
+        // Don't remove anything that's still used.
+        for_all_argument_indexes(&mut fmt.template, |index| remove[*index] = false);
+
+        // Drop all the arguments that are marked for removal.
+        let mut remove_it = remove.iter();
+        fmt.arguments.all_args_mut().retain(|_| remove_it.next() != Some(&true));
+
+        // Calculate the mapping of old to new indexes for the remaining arguments.
+        let index_map: Vec<usize> = remove
+            .into_iter()
+            .scan(0, |i, remove| {
+                let mapped = *i;
+                *i += !remove as usize;
+                Some(mapped)
+            })
+            .collect();
+
+        // Correct the indexes that refer to arguments that have shifted position.
+        for_all_argument_indexes(&mut fmt.template, |index| *index = index_map[*index]);
+    }
+
+    fmt
 }
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@@ -189,11 +348,26 @@ fn expand_format_args<'hir>(
     ctx: &mut LoweringContext<'_, 'hir>,
     macsp: Span,
     fmt: &FormatArgs,
+    allow_const: bool,
 ) -> hir::ExprKind<'hir> {
+    let mut incomplete_lit = String::new();
     let lit_pieces =
         ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| {
             match piece {
-                &FormatArgsPiece::Literal(s) => Some(ctx.expr_str(fmt.span, s)),
+                &FormatArgsPiece::Literal(s) => {
+                    // Coalesce adjacent literal pieces.
+                    if let Some(FormatArgsPiece::Literal(_)) = fmt.template.get(i + 1) {
+                        incomplete_lit.push_str(s.as_str());
+                        None
+                    } else if !incomplete_lit.is_empty() {
+                        incomplete_lit.push_str(s.as_str());
+                        let s = Symbol::intern(&incomplete_lit);
+                        incomplete_lit.clear();
+                        Some(ctx.expr_str(fmt.span, s))
+                    } else {
+                        Some(ctx.expr_str(fmt.span, s))
+                    }
+                }
                 &FormatArgsPiece::Placeholder(_) => {
                     // Inject empty string before placeholders when not already preceded by a literal piece.
                     if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
@@ -244,6 +418,18 @@ fn expand_format_args<'hir>(
 
     let arguments = fmt.arguments.all_args();
 
+    if allow_const && arguments.is_empty() && argmap.is_empty() {
+        // Generate:
+        //     <core::fmt::Arguments>::new_const(lit_pieces)
+        let new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+            macsp,
+            hir::LangItem::FormatArguments,
+            sym::new_const,
+        ));
+        let new_args = ctx.arena.alloc_from_iter([lit_pieces]);
+        return hir::ExprKind::Call(new, new_args);
+    }
+
     // If the args array contains exactly all the original arguments once,
     // in order, we can use a simple array instead of a `match` construction.
     // However, if there's a yield point in any argument except the first one,
@@ -290,25 +476,14 @@ fn expand_format_args<'hir>(
         let args_ident = Ident::new(sym::args, macsp);
         let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
         let args = ctx.arena.alloc_from_iter(argmap.iter().map(|&(arg_index, ty)| {
-            if let Some(arg) = arguments.get(arg_index) {
-                let sp = arg.expr.span.with_ctxt(macsp.ctxt());
-                let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id);
-                let arg = ctx.arena.alloc(ctx.expr(
-                    sp,
-                    hir::ExprKind::Field(
-                        args_ident_expr,
-                        Ident::new(sym::integer(arg_index), macsp),
-                    ),
-                ));
-                make_argument(ctx, sp, arg, ty)
-            } else {
-                ctx.expr(
-                    macsp,
-                    hir::ExprKind::Err(
-                        ctx.tcx.sess.delay_span_bug(macsp, format!("no arg at {arg_index}")),
-                    ),
-                )
-            }
+            let arg = &arguments[arg_index];
+            let sp = arg.expr.span.with_ctxt(macsp.ctxt());
+            let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id);
+            let arg = ctx.arena.alloc(ctx.expr(
+                sp,
+                hir::ExprKind::Field(args_ident_expr, Ident::new(sym::integer(arg_index), macsp)),
+            ));
+            make_argument(ctx, sp, arg, ty)
         }));
         let elements: Vec<_> = arguments
             .iter()
@@ -409,3 +584,22 @@ fn may_contain_yield_point(e: &ast::Expr) -> bool {
     visitor.visit_expr(e);
     visitor.0
 }
+
+fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) {
+    for piece in template {
+        let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
+        if let Ok(index) = &mut placeholder.argument.index {
+            f(index);
+        }
+        if let Some(FormatCount::Argument(FormatArgPosition { index: Ok(index), .. })) =
+            &mut placeholder.format_options.width
+        {
+            f(index);
+        }
+        if let Some(FormatCount::Argument(FormatArgPosition { index: Ok(index), .. })) =
+            &mut placeholder.format_options.precision
+        {
+            f(index);
+        }
+    }
+}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index debe0acb04e..9a117ac9a3c 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1180,7 +1180,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 },
             );
 
-            (this.arena.alloc_from_iter(parameters), this.expr(body.span, async_expr))
+            (this.arena.alloc_from_iter(parameters), async_expr)
         })
     }
 
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 0762987e229..2cbd2e3bc0d 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -306,7 +306,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
         }
 
         // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
-        // pair of array indices are unequal, so that when `places_conflict` returns true, we
+        // pair of array indices are not equal, so that when `places_conflict` returns true, we
         // will be assured that two places being compared definitely denotes the same sets of
         // locations.
         let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index f43b611f54e..75a3dd0c0f3 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -24,6 +24,7 @@ use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{BytePos, Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::ObligationCtxt;
 
 use crate::borrow_set::TwoPhaseActivation;
 use crate::borrowck_errors;
@@ -760,20 +761,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         else { return; };
         // Try to find predicates on *generic params* that would allow copying `ty`
         let infcx = tcx.infer_ctxt().build();
-        let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
-        let cause = ObligationCause::new(
-            span,
-            self.mir_def_id(),
-            rustc_infer::traits::ObligationCauseCode::MiscObligation,
-        );
-        let errors = rustc_trait_selection::traits::fully_solve_bound(
-            &infcx,
-            cause,
-            self.param_env,
-            // Erase any region vids from the type, which may not be resolved
-            infcx.tcx.erase_regions(ty),
-            copy_did,
-        );
+        let ocx = ObligationCtxt::new(&infcx);
+        let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
+        let cause = ObligationCause::misc(span, self.mir_def_id());
+
+        ocx.register_bound(cause, self.param_env, infcx.tcx.erase_regions(ty), copy_did);
+        let errors = ocx.select_all_or_error();
 
         // Only emit suggestion if all required predicates are on generic
         let predicates: Result<Vec<_>, _> = errors
@@ -1985,16 +1978,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
             let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
                 match self.body.local_kind(local) {
-                    LocalKind::ReturnPointer | LocalKind::Temp => {
-                        bug!("temporary or return pointer with a name")
+                    LocalKind::Temp if self.body.local_decls[local].is_user_variable() => {
+                        "local variable "
                     }
-                    LocalKind::Var => "local variable ",
                     LocalKind::Arg
                         if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL =>
                     {
                         "variable captured by `move` "
                     }
                     LocalKind::Arg => "function parameter ",
+                    LocalKind::ReturnPointer | LocalKind::Temp => {
+                        bug!("temporary or return pointer with a name")
+                    }
                 }
             } else {
                 "local data "
@@ -2008,16 +2003,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
             let local = root_place.local;
             match self.body.local_kind(local) {
-                LocalKind::ReturnPointer | LocalKind::Temp => {
-                    ("temporary value".to_string(), "temporary value created here".to_string())
-                }
                 LocalKind::Arg => (
                     "function parameter".to_string(),
                     "function parameter borrowed here".to_string(),
                 ),
-                LocalKind::Var => {
+                LocalKind::Temp if self.body.local_decls[local].is_user_variable() => {
                     ("local binding".to_string(), "local binding introduced here".to_string())
                 }
+                LocalKind::ReturnPointer | LocalKind::Temp => {
+                    ("temporary value".to_string(), "temporary value created here".to_string())
+                }
             }
         };
 
@@ -2482,15 +2477,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let (place_description, assigned_span) = match local_decl {
             Some(LocalDecl {
                 local_info:
-                    Some(box LocalInfo::User(
-                        ClearCrossCrate::Clear
-                        | ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+                    ClearCrossCrate::Set(
+                        box LocalInfo::User(BindingForm::Var(VarBindingForm {
                             opt_match_place: None,
                             ..
-                        })),
-                    ))
-                    | Some(box LocalInfo::StaticRef { .. })
-                    | None,
+                        }))
+                        | box LocalInfo::StaticRef { .. }
+                        | box LocalInfo::Boring,
+                    ),
                 ..
             })
             | None => (self.describe_any_place(place.as_ref()), assigned_span),
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 19855075ced..62b3f3ecfc3 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -6,8 +6,8 @@ use rustc_hir::intravisit::Visitor;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_middle::mir::{
-    Body, CastKind, ConstraintCategory, FakeReadCause, Local, Location, Operand, Place, Rvalue,
-    Statement, StatementKind, TerminatorKind,
+    Body, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place,
+    Rvalue, Statement, StatementKind, TerminatorKind,
 };
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::{self, RegionVid, TyCtxt};
@@ -220,7 +220,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
                         );
                         err.span_label(body.source_info(drop_loc).span, message);
 
-                        if let Some(info) = &local_decl.is_block_tail {
+                        if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
                             if info.tail_result_is_ignored {
                                 // #85581: If the first mutable borrow's scope contains
                                 // the second borrow, this suggestion isn't helpful.
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index af705e6a80f..9f543b71c5f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -196,10 +196,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         if self.body.local_decls[local].is_ref_for_guard() {
                             continue;
                         }
-                        if let Some(box LocalInfo::StaticRef { def_id, .. }) =
-                            &self.body.local_decls[local].local_info
+                        if let LocalInfo::StaticRef { def_id, .. } =
+                            *self.body.local_decls[local].local_info()
                         {
-                            buf.push_str(self.infcx.tcx.item_name(*def_id).as_str());
+                            buf.push_str(self.infcx.tcx.item_name(def_id).as_str());
                             ok = Ok(());
                             continue;
                         }
@@ -1078,7 +1078,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                     self.param_env,
                                     tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)),
                                     def_id,
-                                    DUMMY_SP,
                                 )
                             }
                             _ => false,
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 5e4c7292e59..3662bec0c76 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -102,14 +102,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         //
                         // opt_match_place is None for let [mut] x = ... statements,
                         // whether or not the right-hand side is a place expression
-                        if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
-                            VarBindingForm {
-                                opt_match_place: Some((opt_match_place, match_span)),
-                                binding_mode: _,
-                                opt_ty_info: _,
-                                pat_span: _,
-                            },
-                        )))) = local_decl.local_info
+                        if let LocalInfo::User(BindingForm::Var(VarBindingForm {
+                            opt_match_place: Some((opt_match_place, match_span)),
+                            binding_mode: _,
+                            opt_ty_info: _,
+                            pat_span: _,
+                        })) = *local_decl.local_info()
                         {
                             let stmt_source_info = self.body.source_info(location);
                             self.append_binding_error(
@@ -478,9 +476,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         let mut suggestions: Vec<(Span, String, String)> = Vec::new();
         for local in binds_to {
             let bind_to = &self.body.local_decls[*local];
-            if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
-                VarBindingForm { pat_span, .. },
-            )))) = bind_to.local_info
+            if let LocalInfo::User(BindingForm::Var(VarBindingForm { pat_span, .. })) =
+                *bind_to.local_info()
             {
                 let Ok(pat_snippet) =
                     self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; };
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index eded913ae96..bad08451adf 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -7,7 +7,7 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{
     hir::place::PlaceBase,
-    mir::{self, BindingForm, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location},
+    mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
 };
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::{kw, Symbol};
@@ -105,8 +105,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     reason = String::new();
                 } else {
                     item_msg = access_place_desc;
-                    let local_info = &self.body.local_decls[local].local_info;
-                    if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
+                    let local_info = self.body.local_decls[local].local_info();
+                    if let LocalInfo::StaticRef { def_id, .. } = *local_info {
                         let static_name = &self.infcx.tcx.item_name(def_id);
                         reason = format!(", as `{static_name}` is an immutable static item");
                     } else {
@@ -305,15 +305,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     ..
                 }) = &self.body[location.block].statements.get(location.statement_index)
                 {
-                    match decl.local_info {
-                        Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
-                            mir::VarBindingForm {
-                                binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
-                                opt_ty_info: Some(sp),
-                                opt_match_place: _,
-                                pat_span: _,
-                            },
-                        )))) => {
+                    match *decl.local_info() {
+                        LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
+                            binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
+                            opt_ty_info: Some(sp),
+                            opt_match_place: _,
+                            pat_span: _,
+                        })) => {
                             if suggest {
                                 err.span_note(sp, "the binding is already a mutable borrow");
                             }
@@ -346,10 +344,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     }
                 } else if decl.mutability.is_not() {
                     if matches!(
-                        decl.local_info,
-                        Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
-                            hir::ImplicitSelfKind::MutRef
-                        ),)))
+                        decl.local_info(),
+                        LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::MutRef))
                     ) {
                         err.note(
                             "as `Self` may be unsized, this call attempts to take `&mut &mut self`",
@@ -482,22 +478,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
                 match self.local_names[local] {
                     Some(name) if !local_decl.from_compiler_desugaring() => {
-                        let label = match local_decl.local_info.as_deref().unwrap() {
-                            LocalInfo::User(ClearCrossCrate::Set(
-                                mir::BindingForm::ImplicitSelf(_),
-                            )) => {
+                        let label = match *local_decl.local_info() {
+                            LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
                                 let (span, suggestion) =
                                     suggest_ampmut_self(self.infcx.tcx, local_decl);
                                 Some((true, span, suggestion))
                             }
 
-                            LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
-                                mir::VarBindingForm {
-                                    binding_mode: ty::BindingMode::BindByValue(_),
-                                    opt_ty_info,
-                                    ..
-                                },
-                            ))) => {
+                            LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
+                                binding_mode: ty::BindingMode::BindByValue(_),
+                                opt_ty_info,
+                                ..
+                            })) => {
                                 // check if the RHS is from desugaring
                                 let opt_assignment_rhs_span =
                                     self.body.find_assignments(local).first().map(|&location| {
@@ -534,16 +526,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                                 self.infcx.tcx,
                                                 local_decl,
                                                 opt_assignment_rhs_span,
-                                                *opt_ty_info,
+                                                opt_ty_info,
                                             )
                                         } else {
-                                            match local_decl.local_info.as_deref() {
-                                                Some(LocalInfo::User(ClearCrossCrate::Set(
-                                                    mir::BindingForm::Var(mir::VarBindingForm {
-                                                        opt_ty_info: None,
-                                                        ..
-                                                    }),
-                                                ))) => {
+                                            match local_decl.local_info() {
+                                                LocalInfo::User(mir::BindingForm::Var(
+                                                    mir::VarBindingForm {
+                                                        opt_ty_info: None, ..
+                                                    },
+                                                )) => {
                                                     let (span, sugg) = suggest_ampmut_self(
                                                         self.infcx.tcx,
                                                         local_decl,
@@ -555,7 +546,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                                     self.infcx.tcx,
                                                     local_decl,
                                                     opt_assignment_rhs_span,
-                                                    *opt_ty_info,
+                                                    opt_ty_info,
                                                 ),
                                             }
                                         };
@@ -564,21 +555,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                 }
                             }
 
-                            LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
-                                mir::VarBindingForm {
-                                    binding_mode: ty::BindingMode::BindByReference(_),
-                                    ..
-                                },
-                            ))) => {
+                            LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
+                                binding_mode: ty::BindingMode::BindByReference(_),
+                                ..
+                            })) => {
                                 let pattern_span = local_decl.source_info.span;
                                 suggest_ref_mut(self.infcx.tcx, pattern_span)
                                     .map(|replacement| (true, pattern_span, replacement))
                             }
 
-                            LocalInfo::User(ClearCrossCrate::Clear) => {
-                                bug!("saw cleared local state")
-                            }
-
                             _ => unreachable!(),
                         };
 
@@ -1151,20 +1136,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
     debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
 
-    match local_decl.local_info.as_deref() {
+    match *local_decl.local_info() {
         // Check if mutably borrowing a mutable reference.
-        Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
-            mir::VarBindingForm {
-                binding_mode: ty::BindingMode::BindByValue(Mutability::Not), ..
-            },
-        )))) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
-        Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(kind)))) => {
+        LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
+            binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
+            ..
+        })) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
+        LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => {
             // Check if the user variable is a `&mut self` and we can therefore
             // suggest removing the `&mut`.
             //
             // Deliberately fall into this case for all implicit self types,
             // so that we don't fall in to the next case with them.
-            *kind == hir::ImplicitSelfKind::MutRef
+            kind == hir::ImplicitSelfKind::MutRef
         }
         _ if Some(kw::SelfLower) == local_name => {
             // Otherwise, check if the name is the `self` keyword - in which case
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 5e77f6b190a..2f2f7d0aaa4 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -19,7 +19,6 @@ extern crate tracing;
 
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::graph::dominators::Dominators;
-use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
@@ -141,7 +140,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Bor
         debug!("Skipping borrowck because of injected body");
         // Let's make up a borrowck result! Fun times!
         let result = BorrowCheckResult {
-            concrete_opaque_types: VecMap::new(),
+            concrete_opaque_types: FxIndexMap::default(),
             closure_requirements: None,
             used_mut_upvars: SmallVec::new(),
             tainted_by_errors: None,
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 96228338a4c..f0068fc9226 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -2,7 +2,7 @@
 #![deny(rustc::diagnostic_outside_of_impl)]
 //! The entry point of the NLL borrow checker.
 
-use rustc_data_structures::vec_map::VecMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::def_id::LocalDefId;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere};
@@ -44,7 +44,7 @@ pub type PoloniusOutput = Output<RustcFacts>;
 /// closure requirements to propagate, and any generated errors.
 pub(crate) struct NllOutput<'tcx> {
     pub regioncx: RegionInferenceContext<'tcx>,
-    pub opaque_type_values: VecMap<LocalDefId, OpaqueHiddenType<'tcx>>,
+    pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
     pub polonius_input: Option<Box<AllFacts>>,
     pub polonius_output: Option<Rc<PoloniusOutput>>,
     pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
@@ -377,7 +377,7 @@ pub(super) fn dump_annotation<'tcx>(
     body: &Body<'tcx>,
     regioncx: &RegionInferenceContext<'tcx>,
     closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
-    opaque_type_values: &VecMap<LocalDefId, OpaqueHiddenType<'tcx>>,
+    opaque_type_values: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
     errors: &mut crate::error::BorrowckErrors<'tcx>,
 ) {
     let tcx = infcx.tcx;
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 905d8c42b28..dbf15a3e05f 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -255,7 +255,7 @@ fn sccs_info<'cx, 'tcx>(
     let var_to_origin = infcx.reg_var_to_origin.borrow();
 
     let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>();
-    var_to_origin_sorted.sort_by(|a, b| a.0.cmp(&b.0));
+    var_to_origin_sorted.sort_by_key(|vto| vto.0);
     let mut debug_str = "region variables to origins:\n".to_string();
     for (reg_var, origin) in var_to_origin_sorted.into_iter() {
         debug_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin));
@@ -2216,7 +2216,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // is in the same SCC or something. In that case, find what
         // appears to be the most interesting point to report to the
         // user via an even more ad-hoc guess.
-        categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
+        categorized_path.sort_by_key(|p| p.category);
         debug!("sorted_path={:#?}", categorized_path);
 
         (categorized_path.remove(0), extra_info)
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 748c8b9e442..2b16655cf7d 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -1,5 +1,4 @@
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::OpaqueTyOrigin;
@@ -61,9 +60,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     pub(crate) fn infer_opaque_types(
         &self,
         infcx: &InferCtxt<'tcx>,
-        opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
-    ) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> {
-        let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new();
+        opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
+    ) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
+        let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();
 
         let member_constraints: FxIndexMap<_, _> = self
             .member_constraints
@@ -284,7 +283,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         // hidden type is well formed even without those bounds.
         let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()));
 
-        let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id());
+        let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
 
         // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
         // the bounds that the function supplies.
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 3919c4793a0..f67dae9beb9 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -10,7 +10,6 @@ use either::Either;
 use hir::OpaqueTyOrigin;
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_data_structures::vec_map::VecMap;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
@@ -894,7 +893,7 @@ pub(crate) struct MirTypeckResults<'tcx> {
     pub(crate) constraints: MirTypeckRegionConstraints<'tcx>,
     pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
     pub(crate) opaque_type_values:
-        VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
+        FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
 }
 
 /// A collection of region constraints that must be satisfied for the
@@ -1180,10 +1179,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
                     Some(l)
-                        if matches!(
-                            body.local_decls[l].local_info,
-                            Some(box LocalInfo::AggregateTemp)
-                        ) =>
+                        if matches!(body.local_decls[l].local_info(), LocalInfo::AggregateTemp) =>
                     {
                         ConstraintCategory::Usage
                     }
@@ -1684,7 +1680,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 // - maybe we should make that a warning.
                 return;
             }
-            LocalKind::Var | LocalKind::Temp => {}
+            LocalKind::Temp => {}
         }
 
         // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index e93a23394c0..db2ef7fba4b 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -36,6 +36,21 @@ enum PositionUsedAs {
 }
 use PositionUsedAs::*;
 
+struct MacroInput {
+    fmtstr: P<Expr>,
+    args: FormatArguments,
+    /// Whether the first argument was a string literal or a result from eager macro expansion.
+    /// If it's not a string literal, we disallow implicit arugment capturing.
+    ///
+    /// This does not correspond to whether we can treat spans to the literal normally, as the whole
+    /// invocation might be the result of another macro expansion, in which case this flag may still be true.
+    ///
+    /// See [RFC 2795] for more information.
+    ///
+    /// [RFC 2795]: https://rust-lang.github.io/rfcs/2795-format-args-implicit-identifiers.html#macro-hygiene
+    is_direct_literal: bool,
+}
+
 /// Parses the arguments from the given list of tokens, returning the diagnostic
 /// if there's a parse error so we can continue parsing other format!
 /// expressions.
@@ -45,11 +60,7 @@ use PositionUsedAs::*;
 /// ```text
 /// Ok((fmtstr, parsed arguments))
 /// ```
-fn parse_args<'a>(
-    ecx: &mut ExtCtxt<'a>,
-    sp: Span,
-    tts: TokenStream,
-) -> PResult<'a, (P<Expr>, FormatArguments)> {
+fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> {
     let mut args = FormatArguments::new();
 
     let mut p = ecx.new_parser_from_tts(tts);
@@ -59,25 +70,21 @@ fn parse_args<'a>(
     }
 
     let first_token = &p.token;
-    let fmtstr = match first_token.kind {
-        token::TokenKind::Literal(token::Lit {
-            kind: token::LitKind::Str | token::LitKind::StrRaw(_),
-            ..
-        }) => {
-            // If the first token is a string literal, then a format expression
-            // is constructed from it.
-            //
-            // This allows us to properly handle cases when the first comma
-            // after the format string is mistakenly replaced with any operator,
-            // which cause the expression parser to eat too much tokens.
-            p.parse_literal_maybe_minus()?
-        }
-        _ => {
-            // Otherwise, we fall back to the expression parser.
-            p.parse_expr()?
-        }
+
+    let fmtstr = if let token::Literal(lit) = first_token.kind && matches!(lit.kind, token::Str | token::StrRaw(_)) {
+        // This allows us to properly handle cases when the first comma
+        // after the format string is mistakenly replaced with any operator,
+        // which cause the expression parser to eat too much tokens.
+        p.parse_literal_maybe_minus()?
+    } else {
+        // Otherwise, we fall back to the expression parser.
+        p.parse_expr()?
     };
 
+    // Only allow implicit captures to be used when the argument is a direct literal
+    // instead of a macro expanding to one.
+    let is_direct_literal = matches!(fmtstr.kind, ExprKind::Lit(_));
+
     let mut first = true;
 
     while p.token != token::Eof {
@@ -147,17 +154,19 @@ fn parse_args<'a>(
             }
         }
     }
-    Ok((fmtstr, args))
+    Ok(MacroInput { fmtstr, args, is_direct_literal })
 }
 
-pub fn make_format_args(
+fn make_format_args(
     ecx: &mut ExtCtxt<'_>,
-    efmt: P<Expr>,
-    mut args: FormatArguments,
+    input: MacroInput,
     append_newline: bool,
 ) -> Result<FormatArgs, ()> {
     let msg = "format argument must be a string literal";
-    let unexpanded_fmt_span = efmt.span;
+    let unexpanded_fmt_span = input.fmtstr.span;
+
+    let MacroInput { fmtstr: efmt, mut args, is_direct_literal } = input;
+
     let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) {
         Ok(mut fmt) if append_newline => {
             fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
@@ -208,11 +217,11 @@ pub fn make_format_args(
         }
     }
 
-    let is_literal = parser.is_literal;
+    let is_source_literal = parser.is_source_literal;
 
     if !parser.errors.is_empty() {
         let err = parser.errors.remove(0);
-        let sp = if is_literal {
+        let sp = if is_source_literal {
             fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end))
         } else {
             // The format string could be another macro invocation, e.g.:
@@ -230,7 +239,7 @@ pub fn make_format_args(
         if let Some(note) = err.note {
             e.note(&note);
         }
-        if let Some((label, span)) = err.secondary_label && is_literal {
+        if let Some((label, span)) = err.secondary_label && is_source_literal {
             e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
         }
         if err.should_be_replaced_with_positional_argument {
@@ -256,7 +265,7 @@ pub fn make_format_args(
     }
 
     let to_span = |inner_span: rustc_parse_format::InnerSpan| {
-        is_literal.then(|| {
+        is_source_literal.then(|| {
             fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end })
         })
     };
@@ -304,7 +313,7 @@ pub fn make_format_args(
                     // Name not found in `args`, so we add it as an implicitly captured argument.
                     let span = span.unwrap_or(fmt_span);
                     let ident = Ident::new(name, span);
-                    let expr = if is_literal {
+                    let expr = if is_direct_literal {
                         ecx.expr_ident(span, ident)
                     } else {
                         // For the moment capturing variables from format strings expanded from macros is
@@ -814,7 +823,7 @@ fn report_invalid_references(
         // for `println!("{7:7$}", 1);`
         indexes.sort();
         indexes.dedup();
-        let span: MultiSpan = if !parser.is_literal || parser.arg_places.is_empty() {
+        let span: MultiSpan = if !parser.is_source_literal || parser.arg_places.is_empty() {
             MultiSpan::from_span(fmt_span)
         } else {
             MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect())
@@ -855,8 +864,8 @@ fn expand_format_args_impl<'cx>(
 ) -> Box<dyn base::MacResult + 'cx> {
     sp = ecx.with_def_site_ctxt(sp);
     match parse_args(ecx, sp, tts) {
-        Ok((efmt, args)) => {
-            if let Ok(format_args) = make_format_args(ecx, efmt, args, nl) {
+        Ok(input) => {
+            if let Ok(format_args) = make_format_args(ecx, input, nl) {
                 MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args))))
             } else {
                 MacEager::expr(DummyResult::raw_expr(sp, true))
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index e02c7e6c01b..151afd2d458 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -8,7 +8,7 @@ use rustc_errors::Applicability;
 use rustc_expand::base::*;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{FileNameDisplayPreference, Span};
 use std::iter;
 use thin_vec::{thin_vec, ThinVec};
 
@@ -33,7 +33,23 @@ pub fn expand_test_case(
     }
 
     let sp = ecx.with_def_site_ctxt(attr_sp);
-    let mut item = anno_item.expect_item();
+    let (mut item, is_stmt) = match anno_item {
+        Annotatable::Item(item) => (item, false),
+        Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => if let ast::StmtKind::Item(i) = stmt.into_inner().kind {
+            (i, true)
+        } else {
+            unreachable!()
+        },
+        _ => {
+            ecx.struct_span_err(
+                anno_item.span(),
+                "`#[test_case]` attribute is only allowed on items",
+            )
+            .emit();
+
+            return vec![];
+        }
+    };
     item = item.map(|mut item| {
         let test_path_symbol = Symbol::intern(&item_path(
             // skip the name of the root module
@@ -50,7 +66,13 @@ pub fn expand_test_case(
         item
     });
 
-    return vec![Annotatable::Item(item)];
+    let ret = if is_stmt {
+        Annotatable::Stmt(P(ecx.stmt_item(item.span, item)))
+    } else {
+        Annotatable::Item(item)
+    };
+
+    vec![ret]
 }
 
 pub fn expand_test(
@@ -231,6 +253,8 @@ pub fn expand_test_or_bench(
         &item.ident,
     ));
 
+    let location_info = get_location_info(cx, &item);
+
     let mut test_const = cx.item(
         sp,
         Ident::new(item.ident.name, sp),
@@ -280,6 +304,16 @@ pub fn expand_test_or_bench(
                                             cx.expr_none(sp)
                                         },
                                     ),
+                                    // source_file: <relative_path_of_source_file>
+                                    field("source_file", cx.expr_str(sp, location_info.0)),
+                                    // start_line: start line of the test fn identifier.
+                                    field("start_line", cx.expr_usize(sp, location_info.1)),
+                                    // start_col: start column of the test fn identifier.
+                                    field("start_col", cx.expr_usize(sp, location_info.2)),
+                                    // end_line: end line of the test fn identifier.
+                                    field("end_line", cx.expr_usize(sp, location_info.3)),
+                                    // end_col: end column of the test fn identifier.
+                                    field("end_col", cx.expr_usize(sp, location_info.4)),
                                     // compile_fail: true | false
                                     field("compile_fail", cx.expr_bool(sp, false)),
                                     // no_run: true | false
@@ -364,6 +398,19 @@ pub fn expand_test_or_bench(
     }
 }
 
+fn get_location_info(cx: &ExtCtxt<'_>, item: &ast::Item) -> (Symbol, usize, usize, usize, usize) {
+    let span = item.ident.span;
+    let (source_file, lo_line, lo_col, hi_line, hi_col) =
+        cx.sess.source_map().span_to_location_info(span);
+
+    let file_name = match source_file {
+        Some(sf) => sf.name.display(FileNameDisplayPreference::Remapped).to_string(),
+        None => "no-location".to_string(),
+    };
+
+    (Symbol::intern(&file_name), lo_line, lo_col, hi_line, hi_col)
+}
+
 fn item_path(mod_path: &[Ident], item_ident: &Ident) -> String {
     mod_path
         .iter()
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
new file mode 100644
index 00000000000..5f5510a5796
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
@@ -0,0 +1,64 @@
+name: Abi-cafe
+
+on:
+  - push
+
+jobs:
+  abi_cafe:
+    runs-on: ${{ matrix.os }}
+    timeout-minutes: 60
+    concurrency:
+      group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.os }}-${{ matrix.env.TARGET_TRIPLE }}
+      cancel-in-progress: true
+
+    defaults:
+      run:
+        shell: bash
+
+    strategy:
+      fail-fast: true
+      matrix:
+        include:
+          - os: ubuntu-latest
+            env:
+              TARGET_TRIPLE: x86_64-unknown-linux-gnu
+          - os: macos-latest
+            env:
+              TARGET_TRIPLE: x86_64-apple-darwin
+          - os: windows-latest
+            env:
+              TARGET_TRIPLE: x86_64-pc-windows-msvc
+          - os: windows-latest
+            env:
+              TARGET_TRIPLE: x86_64-pc-windows-gnu
+
+    steps:
+    - uses: actions/checkout@v3
+
+    - name: Cache cargo target dir
+      uses: actions/cache@v3
+      with:
+        path: build/cg_clif
+        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+
+    - name: Set MinGW as the default toolchain
+      if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
+      run: rustup set default-host x86_64-pc-windows-gnu
+
+    - name: Use sparse cargo registry
+      run: |
+        cat >> ~/.cargo/config.toml <<EOF
+        [unstable]
+        sparse-registry = true
+        EOF
+
+    - name: Prepare dependencies
+      run: ./y.rs prepare
+
+    - name: Build
+      run: ./y.rs build --sysroot none
+
+    - name: Test abi-cafe
+      env:
+        TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
+      run: ./y.rs abi-cafe
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index 9d3ed3ac5d0..98b34c65dea 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -22,7 +22,7 @@ jobs:
         rustfmt --check build_system/mod.rs
 
 
-  build:
+  test:
     runs-on: ${{ matrix.os }}
     timeout-minutes: 60
 
@@ -114,63 +114,6 @@ jobs:
       run: ./y.rs test
 
 
-  abi_cafe:
-    runs-on: ${{ matrix.os }}
-    timeout-minutes: 60
-
-    defaults:
-      run:
-        shell: bash
-
-    strategy:
-      fail-fast: true
-      matrix:
-        include:
-          - os: ubuntu-latest
-            env:
-              TARGET_TRIPLE: x86_64-unknown-linux-gnu
-          - os: macos-latest
-            env:
-              TARGET_TRIPLE: x86_64-apple-darwin
-          - os: windows-latest
-            env:
-              TARGET_TRIPLE: x86_64-pc-windows-msvc
-          - os: windows-latest
-            env:
-              TARGET_TRIPLE: x86_64-pc-windows-gnu
-
-    steps:
-    - uses: actions/checkout@v3
-
-    - name: Cache cargo target dir
-      uses: actions/cache@v3
-      with:
-        path: build/cg_clif
-        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
-
-    - name: Set MinGW as the default toolchain
-      if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
-      run: rustup set default-host x86_64-pc-windows-gnu
-
-    - name: Use sparse cargo registry
-      run: |
-        cat >> ~/.cargo/config.toml <<EOF
-        [unstable]
-        sparse-registry = true
-        EOF
-
-    - name: Prepare dependencies
-      run: ./y.rs prepare
-
-    - name: Build
-      run: ./y.rs build --sysroot none
-
-    - name: Test abi-cafe
-      env:
-        TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
-      run: ./y.rs abi-cafe
-
-
   bench:
     runs-on: ubuntu-latest
     timeout-minutes: 60
diff --git a/compiler/rustc_codegen_cranelift/.gitignore b/compiler/rustc_codegen_cranelift/.gitignore
index 8012e93f6a9..e5d10a937ae 100644
--- a/compiler/rustc_codegen_cranelift/.gitignore
+++ b/compiler/rustc_codegen_cranelift/.gitignore
@@ -14,3 +14,4 @@ perf.data.old
 /dist
 /rust
 /download
+/git-fixed-subtree.sh
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 50249ea1bdb..157ef4bf389 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -57,18 +57,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.92.0"
+version = "0.93.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f3d54eab028f5805ae3b26fd60eca3f3a9cfb76b989d9bab173be3f61356cc3"
+checksum = "a7379abaacee0f14abf3204a7606118f0465785252169d186337bcb75030815a"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.92.0"
+version = "0.93.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2be1d5f2c3cca1efb691844bc1988b89c77291f13f778499a3f3c0cf49c0ed61"
+checksum = "9489fa336927df749631f1008007ced2871068544f40a202ce6d93fbf2366a7b"
 dependencies = [
  "arrayvec",
  "bumpalo",
@@ -87,30 +87,30 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.92.0"
+version = "0.93.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9b1b1089750ce4005893af7ee00bb08a2cf1c9779999c0f7164cbc8ad2e0d2"
+checksum = "05bbb67da91ec721ed57cef2f7c5ef7728e1cd9bde9ffd3ef8601022e73e3239"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.92.0"
+version = "0.93.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc5fbaec51de47297fd7304986fd53c8c0030abbe69728a60d72e1c63559318d"
+checksum = "418ecb2f36032f6665dc1a5e2060a143dbab41d83b784882e97710e890a7a16d"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.92.0"
+version = "0.93.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dab984c94593f876090fae92e984bdcc74d9b1acf740ab5f79036001c65cba13"
+checksum = "7cf583f7b093f291005f9fb1323e2c37f6ee4c7909e39ce016b2e8360d461705"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.92.0"
+version = "0.93.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e0cb3102d21a2fe5f3210af608748ddd0cd09825ac12d42dc56ed5ed8725fe0"
+checksum = "7d361ed0373cf5f086b49c499aa72227b646a64f899f32e34312f97c0fadff75"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -120,15 +120,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.92.0"
+version = "0.93.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72101dd1f441d629735143c41e00b3428f9267738176983ef588ff43382af0a0"
+checksum = "649782a39ce99798dd6b4029e2bb318a2fbeaade1b4fa25330763c10c65bc358"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.92.0"
+version = "0.93.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6557f8ce44d498777f2495aa58d9692a4a37d6f84aa445750d666cef770b6a5c"
+checksum = "9c9909222db472fcc98d9e4e7192fa9d064dac63a3fa657df8c6daae86fb2604"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -145,9 +145,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.92.0"
+version = "0.93.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88807e1c0c47ec02fe433333ccbe56b480425418b1470e333205e11650697d72"
+checksum = "68689b83e52e605ba48652882d3fccc2e2e136abf139eb64ae667888ba0d52f8"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -155,9 +155,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.92.0"
+version = "0.93.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c22b0d9fcbe3fc5a1af9e7021b44ce42b930bcefac446ce22e02e8f9a0d67120"
+checksum = "f98e4e99a353703475d5acb402b9c13482d41d8a4008b352559bd560afb90363"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -166,9 +166,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.92.0"
+version = "0.93.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "341375758d7c3fedc0b5315f552e6f0feac46baf87c450a15e9455ef47c2b261"
+checksum = "b7a006ce1d8dd11df67567d8673e5920f3a56441812aed52a007ffce8f1b20e9"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -333,6 +333,7 @@ dependencies = [
  "cranelift-frontend",
  "cranelift-jit",
  "cranelift-module",
+ "cranelift-native",
  "cranelift-object",
  "gimli",
  "indexmap",
@@ -381,9 +382,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasmtime-jit-icache-coherence"
-version = "5.0.0"
+version = "6.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08fcba5ebd96da2a9f0747ab6337fe9788adfb3f63fa2c180520d665562d257e"
+checksum = "ec1fd0f0dd79e7cc0f55b102e320d7c77ab76cd272008a8fd98e25b5777e2636"
 dependencies = [
  "cfg-if",
  "libc",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 34117c2886f..0e64fba6bec 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -15,14 +15,12 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.92", features = ["unwind", "all-arch"] }
-cranelift-frontend = { version = "0.92" }
-cranelift-module = { version = "0.92" }
-# NOTE vendored as src/cranelift_native.rs
-# FIXME revert back to the external crate with Cranelift 0.93
-#cranelift-native = { version = "0.92" }
-cranelift-jit = { version = "0.92", optional = true }
-cranelift-object = { version = "0.92" }
+cranelift-codegen = { version = "0.93", features = ["unwind", "all-arch"] }
+cranelift-frontend = { version = "0.93" }
+cranelift-module = { version = "0.93" }
+cranelift-native = { version = "0.93" }
+cranelift-jit = { version = "0.93", optional = true }
+cranelift-object = { version = "0.93" }
 target-lexicon = "0.12.0"
 gimli = { version = "0.26.0", default-features = false, features = ["write"]}
 object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
index b7e0b68a2a2..f2150762991 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
@@ -50,9 +50,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.86"
+version = "0.1.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dae98c88e576098d7ab13ebcb40cc43e5114b2beafe61a87cda9200649ff205"
+checksum = "9fc9c2080d347a2c316518840ac9194644a9993dfa1e9778ef38979a339f5d8b"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -117,21 +117,20 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.2.6"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
+checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
 dependencies = [
  "compiler_builtins",
- "libc",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
 [[package]]
 name = "libc"
-version = "0.2.139"
+version = "0.2.140"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
+checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -282,10 +281,8 @@ dependencies = [
 name = "test"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
  "core",
  "getopts",
- "libc",
  "panic_abort",
  "panic_unwind",
  "proc_macro",
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml
index d0e5fc4a3b9..8219e6b6ccf 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml
@@ -8,7 +8,7 @@ alloc = { path = "./sysroot_src/library/alloc" }
 std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
 test = { path = "./sysroot_src/library/test" }
 
-compiler_builtins = { version = "0.1.39", default-features = false, features = ["no-asm"] }
+compiler_builtins = { version = "0.1.87", default-features = false, features = ["no-asm"] }
 
 [patch.crates-io]
 rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
index 2e04f2c6811..76b602fe719 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
@@ -46,13 +46,15 @@ pub(crate) fn build_sysroot(
         let wrapper_name = wrapper_base_name.replace("____", wrapper);
 
         let mut build_cargo_wrapper_cmd = Command::new(&bootstrap_host_compiler.rustc);
+        let wrapper_path = DIST_DIR.to_path(dirs).join(&wrapper_name);
         build_cargo_wrapper_cmd
             .env("TOOLCHAIN_NAME", toolchain_name.clone())
             .arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs")))
             .arg("-o")
-            .arg(DIST_DIR.to_path(dirs).join(wrapper_name))
+            .arg(&wrapper_path)
             .arg("-Cstrip=debuginfo");
         spawn_and_wait(build_cargo_wrapper_cmd);
+        try_hard_link(wrapper_path, BIN_DIR.to_path(dirs).join(wrapper_name));
     }
 
     let host = build_sysroot_for_triple(
@@ -247,6 +249,7 @@ fn build_clif_sysroot_for_triple(
     if channel == "release" {
         build_cmd.arg("--release");
     }
+    build_cmd.arg("--locked");
     build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
     if compiler.triple.contains("apple") {
         build_cmd.env("CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO", "packed");
diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
index 50b1b7836de..6769e42d44b 100644
--- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
@@ -6,6 +6,7 @@ use std::process::Command;
 use super::build_sysroot::{BUILD_SYSROOT, ORIG_BUILD_SYSROOT, SYSROOT_RUSTC_VERSION, SYSROOT_SRC};
 use super::path::{Dirs, RelPath};
 use super::rustc_info::{get_default_sysroot, get_rustc_version};
+use super::tests::LIBCORE_TESTS_SRC;
 use super::utils::{copy_dir_recursively, git_command, retry_spawn_and_wait, spawn_and_wait};
 
 pub(crate) fn prepare(dirs: &Dirs) {
@@ -13,8 +14,10 @@ pub(crate) fn prepare(dirs: &Dirs) {
 
     spawn_and_wait(super::build_backend::CG_CLIF.fetch("cargo", "rustc", dirs));
 
-    prepare_sysroot(dirs);
+    prepare_stdlib(dirs);
     spawn_and_wait(super::build_sysroot::STANDARD_LIBRARY.fetch("cargo", "rustc", dirs));
+
+    prepare_coretests(dirs);
     spawn_and_wait(super::tests::LIBCORE_TESTS.fetch("cargo", "rustc", dirs));
 
     super::tests::RAND_REPO.fetch(dirs);
@@ -25,11 +28,11 @@ pub(crate) fn prepare(dirs: &Dirs) {
     spawn_and_wait(super::tests::PORTABLE_SIMD.fetch("cargo", "rustc", dirs));
 }
 
-fn prepare_sysroot(dirs: &Dirs) {
+fn prepare_stdlib(dirs: &Dirs) {
     let sysroot_src_orig = get_default_sysroot(Path::new("rustc")).join("lib/rustlib/src/rust");
     assert!(sysroot_src_orig.exists());
 
-    eprintln!("[COPY] sysroot src");
+    eprintln!("[COPY] stdlib src");
 
     // FIXME ensure builds error out or update the copy if any of the files copied here change
     BUILD_SYSROOT.ensure_fresh(dirs);
@@ -47,7 +50,25 @@ fn prepare_sysroot(dirs: &Dirs) {
     eprintln!("[GIT] init");
     init_git_repo(&SYSROOT_SRC.to_path(dirs));
 
-    apply_patches(dirs, "sysroot", &SYSROOT_SRC.to_path(dirs));
+    apply_patches(dirs, "stdlib", &SYSROOT_SRC.to_path(dirs));
+}
+
+fn prepare_coretests(dirs: &Dirs) {
+    let sysroot_src_orig = get_default_sysroot(Path::new("rustc")).join("lib/rustlib/src/rust");
+    assert!(sysroot_src_orig.exists());
+
+    eprintln!("[COPY] coretests src");
+
+    fs::create_dir_all(LIBCORE_TESTS_SRC.to_path(dirs)).unwrap();
+    copy_dir_recursively(
+        &sysroot_src_orig.join("library/core/tests"),
+        &LIBCORE_TESTS_SRC.to_path(dirs),
+    );
+
+    eprintln!("[GIT] init");
+    init_git_repo(&LIBCORE_TESTS_SRC.to_path(dirs));
+
+    apply_patches(dirs, "coretests", &LIBCORE_TESTS_SRC.to_path(dirs));
 }
 
 pub(crate) struct GitRepo {
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index e9486888f86..261948a6971 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -1,4 +1,4 @@
-use super::build_sysroot::{self, SYSROOT_SRC};
+use super::build_sysroot;
 use super::config;
 use super::path::{Dirs, RelPath};
 use super::prepare::GitRepo;
@@ -94,40 +94,42 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
     TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
 ];
 
+// FIXME(rust-random/rand#1293): Newer rand versions fail to test on Windows. Update once this is
+// fixed.
 pub(crate) static RAND_REPO: GitRepo =
-    GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
+    GitRepo::github("rust-random", "rand", "50b9a447410860af8d6db9a208c3576886955874", "rand");
 
 pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
 
 pub(crate) static REGEX_REPO: GitRepo =
-    GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
+    GitRepo::github("rust-lang", "regex", "a9b2e02352db92ce1f6e5b7ecd41b8bbffbe161a", "regex");
 
 pub(crate) static REGEX: CargoProject = CargoProject::new(&REGEX_REPO.source_dir(), "regex");
 
 pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
     "rust-lang",
     "portable-simd",
-    "582239ac3b32007613df04d7ffa78dc30f4c5645",
+    "9bd30e77b3a3c699af102ebb3df0f6110f8aa02e",
     "portable-simd",
 );
 
 pub(crate) static PORTABLE_SIMD: CargoProject =
     CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable_simd");
 
-pub(crate) static LIBCORE_TESTS: CargoProject =
-    CargoProject::new(&SYSROOT_SRC.join("library/core/tests"), "core_tests");
+pub(crate) static LIBCORE_TESTS_SRC: RelPath = RelPath::DOWNLOAD.join("coretests_src");
+
+pub(crate) static LIBCORE_TESTS: CargoProject = CargoProject::new(&LIBCORE_TESTS_SRC, "core_tests");
 
 const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
     TestCase::custom("test.rust-random/rand", &|runner| {
         RAND.clean(&runner.dirs);
 
         if runner.is_native {
-            eprintln!("[TEST] rust-random/rand");
             let mut test_cmd = RAND.test(&runner.target_compiler, &runner.dirs);
-            test_cmd.arg("--workspace");
+            test_cmd.arg("--workspace").arg("--").arg("-q");
             spawn_and_wait(test_cmd);
         } else {
-            eprintln!("[AOT] rust-random/rand");
+            eprintln!("Cross-Compiling: Not running tests");
             let mut build_cmd = RAND.build(&runner.target_compiler, &runner.dirs);
             build_cmd.arg("--workspace").arg("--tests");
             spawn_and_wait(build_cmd);
@@ -137,7 +139,9 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
         LIBCORE_TESTS.clean(&runner.dirs);
 
         if runner.is_native {
-            spawn_and_wait(LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs));
+            let mut test_cmd = LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs);
+            test_cmd.arg("--").arg("-q");
+            spawn_and_wait(test_cmd);
         } else {
             eprintln!("Cross-Compiling: Not running tests");
             let mut build_cmd = LIBCORE_TESTS.build(&runner.target_compiler, &runner.dirs);
@@ -148,18 +152,13 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
     TestCase::custom("test.regex-shootout-regex-dna", &|runner| {
         REGEX.clean(&runner.dirs);
 
-        // newer aho_corasick versions throw a deprecation warning
-        let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
-
         let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
         build_cmd.arg("--example").arg("shootout-regex-dna");
-        build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
         spawn_and_wait(build_cmd);
 
         if runner.is_native {
             let mut run_cmd = REGEX.run(&runner.target_compiler, &runner.dirs);
             run_cmd.arg("--example").arg("shootout-regex-dna");
-            run_cmd.env("RUSTFLAGS", lint_rust_flags);
 
             let input = fs::read_to_string(
                 REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-input.txt"),
@@ -171,13 +170,6 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
             .unwrap();
 
             let output = spawn_and_wait_with_input(run_cmd, input);
-            // Make sure `[codegen mono items] start` doesn't poison the diff
-            let output = output
-                .lines()
-                .filter(|line| !line.contains("codegen mono items"))
-                .chain(Some("")) // This just adds the trailing newline
-                .collect::<Vec<&str>>()
-                .join("\r\n");
 
             let output_matches = expected.lines().eq(output.lines());
             if !output_matches {
@@ -192,27 +184,14 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
     TestCase::custom("test.regex", &|runner| {
         REGEX.clean(&runner.dirs);
 
-        // newer aho_corasick versions throw a deprecation warning
-        let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
-
         if runner.is_native {
             let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs);
-            run_cmd.args([
-                "--tests",
-                "--",
-                "--exclude-should-panic",
-                "--test-threads",
-                "1",
-                "-Zunstable-options",
-                "-q",
-            ]);
-            run_cmd.env("RUSTFLAGS", lint_rust_flags);
+            run_cmd.args(["--workspace", "--", "-q"]);
             spawn_and_wait(run_cmd);
         } else {
             eprintln!("Cross-Compiling: Not running tests");
             let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
             build_cmd.arg("--tests");
-            build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
             spawn_and_wait(build_cmd);
         }
     }),
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 1f9db1eb2a9..73b83b89f6d 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -518,6 +518,17 @@ pub struct Box<T: ?Sized>(Unique<T>, ());
 
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
 
+impl<T> Box<T> {
+    pub fn new(val: T) -> Box<T> {
+        unsafe {
+            let size = intrinsics::size_of::<T>();
+            let ptr = libc::malloc(size);
+            intrinsics::copy(&val as *const T as *const u8, ptr, size);
+            Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, ())
+        }
+    }
+}
+
 impl<T: ?Sized> Drop for Box<T> {
     fn drop(&mut self) {
         // drop is currently performed by compiler.
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 04e7795bbfa..6ad3268e70d 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -1,16 +1,16 @@
-#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local)]
+#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)]
 #![no_core]
 #![allow(dead_code, non_camel_case_types)]
 
 extern crate mini_core;
 
-use mini_core::*;
 use mini_core::libc::*;
+use mini_core::*;
 
 macro_rules! assert {
     ($e:expr) => {
         if !$e {
-            panic(stringify!(! $e));
+            panic(stringify!(!$e));
         }
     };
 }
@@ -20,7 +20,7 @@ macro_rules! assert_eq {
         if $l != $r {
             panic(stringify!($l != $r));
         }
-    }
+    };
 }
 
 #[lang = "termination"]
@@ -96,9 +96,15 @@ fn start<T: Termination + 'static>(
     _sigpipe: u8,
 ) -> isize {
     if argc == 3 {
-        unsafe { puts(*argv as *const i8); }
-        unsafe { puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const i8)); }
-        unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const i8)); }
+        unsafe {
+            puts(*argv as *const i8);
+        }
+        unsafe {
+            puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const i8));
+        }
+        unsafe {
+            puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const i8));
+        }
     }
 
     main().report() as isize
@@ -107,7 +113,6 @@ fn start<T: Termination + 'static>(
 static mut NUM: u8 = 6 * 7;
 static NUM_REF: &'static u8 = unsafe { &NUM };
 
-
 unsafe fn zeroed<T>() -> T {
     let mut uninit = MaybeUninit { uninit: () };
     intrinsics::write_bytes(&mut uninit.value.value as *mut T, 0, 1);
@@ -144,10 +149,7 @@ extern "C" fn bool_struct_in_11(_arg0: bool_11) {}
 
 #[allow(unreachable_code)] // FIXME false positive
 fn main() {
-    take_unique(Unique {
-        pointer: unsafe { NonNull(1 as *mut ()) },
-        _marker: PhantomData,
-    });
+    take_unique(Unique { pointer: unsafe { NonNull(1 as *mut ()) }, _marker: PhantomData });
     take_f32(0.1);
 
     call_return_u128_pair();
@@ -202,17 +204,17 @@ fn main() {
         assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
 
         assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
-        assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8);
+        assert_eq!(
+            intrinsics::min_align_of_val(&a) as u8,
+            intrinsics::min_align_of::<&str>() as u8
+        );
 
         assert!(!intrinsics::needs_drop::<u8>());
         assert!(!intrinsics::needs_drop::<[u8]>());
         assert!(intrinsics::needs_drop::<NoisyDrop>());
         assert!(intrinsics::needs_drop::<NoisyDropUnsized>());
 
-        Unique {
-            pointer: NonNull(1 as *mut &str),
-            _marker: PhantomData,
-        } as Unique<dyn SomeTrait>;
+        Unique { pointer: NonNull(1 as *mut &str), _marker: PhantomData } as Unique<dyn SomeTrait>;
 
         struct MyDst<T: ?Sized>(T);
 
@@ -238,19 +240,17 @@ fn main() {
         }
     }
 
-    let _ = Box::new(NoisyDrop {
-        text: "Boxed outer got dropped!\0",
-        inner: NoisyDropInner,
-    }) as Box<dyn SomeTrait>;
+    let _ = Box::new(NoisyDrop { text: "Boxed outer got dropped!\0", inner: NoisyDropInner })
+        as Box<dyn SomeTrait>;
 
     const FUNC_REF: Option<fn()> = Some(main);
     match FUNC_REF {
-        Some(_) => {},
+        Some(_) => {}
         None => assert!(false),
     }
 
     match Ordering::Less {
-        Ordering::Less => {},
+        Ordering::Less => {}
         _ => assert!(false),
     }
 
@@ -266,19 +266,21 @@ fn main() {
 
     #[cfg(not(any(jit, windows)))]
     {
-        extern {
+        extern "C" {
             #[linkage = "extern_weak"]
             static ABC: *const u8;
         }
 
         {
-            extern {
+            extern "C" {
                 #[linkage = "extern_weak"]
                 static ABC: *const u8;
             }
         }
 
-        unsafe { assert_eq!(ABC as usize, 0); }
+        unsafe {
+            assert_eq!(ABC as usize, 0);
+        }
     }
 
     &mut (|| Some(0 as *const ())) as &mut dyn FnMut() -> Option<*const ()>;
@@ -339,7 +341,13 @@ fn main() {
 
         assert_eq!(unsafe { intrinsics::size_of_val(x) }, 0);
         assert_eq!(unsafe { intrinsics::min_align_of_val(x) }, 1);
-}
+    }
+
+    #[repr(simd)]
+    struct V([f64; 2]);
+
+    let f = V([0.0, 1.0]);
+    let _a = f.0[0];
 }
 
 #[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "darwin")))]
@@ -392,13 +400,10 @@ extern "C" {
         native: *mut pthread_t,
         attr: *const pthread_attr_t,
         f: extern "C" fn(_: *mut c_void) -> *mut c_void,
-        value: *mut c_void
+        value: *mut c_void,
     ) -> c_int;
 
-    fn pthread_join(
-        native: pthread_t,
-        value: *mut *mut c_void
-    ) -> c_int;
+    fn pthread_join(native: pthread_t, value: *mut *mut c_void) -> c_int;
 }
 
 type DWORD = u32;
@@ -410,10 +415,7 @@ type HANDLE = *mut c_void;
 #[link(name = "msvcrt")]
 #[cfg(windows)]
 extern "C" {
-    fn WaitForSingleObject(
-        hHandle: LPVOID,
-        dwMilliseconds: DWORD
-    ) -> DWORD;
+    fn WaitForSingleObject(hHandle: LPVOID, dwMilliseconds: DWORD) -> DWORD;
 
     fn CreateThread(
         lpThreadAttributes: LPVOID, // Technically LPSECURITY_ATTRIBUTES, but we don't use it anyway
@@ -421,7 +423,7 @@ extern "C" {
         lpStartAddress: extern "C" fn(_: *mut c_void) -> *mut c_void,
         lpParameter: LPVOID,
         dwCreationFlags: DWORD,
-        lpThreadId: LPDWORD
+        lpThreadId: LPDWORD,
     ) -> HANDLE;
 }
 
@@ -447,9 +449,7 @@ impl Thread {
                 assert!(false);
             }
 
-            Thread {
-                handle: thread,
-            }
+            Thread { handle: thread }
         }
 
         #[cfg(windows)]
@@ -460,13 +460,10 @@ impl Thread {
                 assert!(false);
             }
 
-            Thread {
-                handle,
-            }
+            Thread { handle }
         }
     }
 
-
     unsafe fn join(self) {
         #[cfg(unix)]
         {
@@ -483,16 +480,15 @@ impl Thread {
     }
 }
 
-
-
-
 #[thread_local]
 #[cfg(not(jit))]
 static mut TLS: u8 = 42;
 
 #[cfg(not(jit))]
 extern "C" fn mutate_tls(_: *mut c_void) -> *mut c_void {
-    unsafe { TLS = 0; }
+    unsafe {
+        TLS = 0;
+    }
     0 as *mut c_void
 }
 
@@ -531,44 +527,267 @@ pub enum E1 {
 pub enum E2<X> {
     V1 { f: bool },
 
-    /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X),
-    _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X),
-    _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X),
-    _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X),
-    _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X),
-    _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X),
-    _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X),
-    _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X),
-    _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X),
-    _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X),
-    _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X),
-    _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X),
-    _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X),
-    _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X),
-    _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X),
-    _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X),
-    _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X),
-    _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X),
-    _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X),
-    _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X),
-    _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X),
-    _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X),
-    _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X),
-    _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X),
-    _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X),
-    _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X),
-    _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X),
-    _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X),
-    _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X),
-    _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X),
-    _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X),
-    _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X),
+    /*_00*/ _01(X),
+    _02(X),
+    _03(X),
+    _04(X),
+    _05(X),
+    _06(X),
+    _07(X),
+    _08(X),
+    _09(X),
+    _0A(X),
+    _0B(X),
+    _0C(X),
+    _0D(X),
+    _0E(X),
+    _0F(X),
+    _10(X),
+    _11(X),
+    _12(X),
+    _13(X),
+    _14(X),
+    _15(X),
+    _16(X),
+    _17(X),
+    _18(X),
+    _19(X),
+    _1A(X),
+    _1B(X),
+    _1C(X),
+    _1D(X),
+    _1E(X),
+    _1F(X),
+    _20(X),
+    _21(X),
+    _22(X),
+    _23(X),
+    _24(X),
+    _25(X),
+    _26(X),
+    _27(X),
+    _28(X),
+    _29(X),
+    _2A(X),
+    _2B(X),
+    _2C(X),
+    _2D(X),
+    _2E(X),
+    _2F(X),
+    _30(X),
+    _31(X),
+    _32(X),
+    _33(X),
+    _34(X),
+    _35(X),
+    _36(X),
+    _37(X),
+    _38(X),
+    _39(X),
+    _3A(X),
+    _3B(X),
+    _3C(X),
+    _3D(X),
+    _3E(X),
+    _3F(X),
+    _40(X),
+    _41(X),
+    _42(X),
+    _43(X),
+    _44(X),
+    _45(X),
+    _46(X),
+    _47(X),
+    _48(X),
+    _49(X),
+    _4A(X),
+    _4B(X),
+    _4C(X),
+    _4D(X),
+    _4E(X),
+    _4F(X),
+    _50(X),
+    _51(X),
+    _52(X),
+    _53(X),
+    _54(X),
+    _55(X),
+    _56(X),
+    _57(X),
+    _58(X),
+    _59(X),
+    _5A(X),
+    _5B(X),
+    _5C(X),
+    _5D(X),
+    _5E(X),
+    _5F(X),
+    _60(X),
+    _61(X),
+    _62(X),
+    _63(X),
+    _64(X),
+    _65(X),
+    _66(X),
+    _67(X),
+    _68(X),
+    _69(X),
+    _6A(X),
+    _6B(X),
+    _6C(X),
+    _6D(X),
+    _6E(X),
+    _6F(X),
+    _70(X),
+    _71(X),
+    _72(X),
+    _73(X),
+    _74(X),
+    _75(X),
+    _76(X),
+    _77(X),
+    _78(X),
+    _79(X),
+    _7A(X),
+    _7B(X),
+    _7C(X),
+    _7D(X),
+    _7E(X),
+    _7F(X),
+    _80(X),
+    _81(X),
+    _82(X),
+    _83(X),
+    _84(X),
+    _85(X),
+    _86(X),
+    _87(X),
+    _88(X),
+    _89(X),
+    _8A(X),
+    _8B(X),
+    _8C(X),
+    _8D(X),
+    _8E(X),
+    _8F(X),
+    _90(X),
+    _91(X),
+    _92(X),
+    _93(X),
+    _94(X),
+    _95(X),
+    _96(X),
+    _97(X),
+    _98(X),
+    _99(X),
+    _9A(X),
+    _9B(X),
+    _9C(X),
+    _9D(X),
+    _9E(X),
+    _9F(X),
+    _A0(X),
+    _A1(X),
+    _A2(X),
+    _A3(X),
+    _A4(X),
+    _A5(X),
+    _A6(X),
+    _A7(X),
+    _A8(X),
+    _A9(X),
+    _AA(X),
+    _AB(X),
+    _AC(X),
+    _AD(X),
+    _AE(X),
+    _AF(X),
+    _B0(X),
+    _B1(X),
+    _B2(X),
+    _B3(X),
+    _B4(X),
+    _B5(X),
+    _B6(X),
+    _B7(X),
+    _B8(X),
+    _B9(X),
+    _BA(X),
+    _BB(X),
+    _BC(X),
+    _BD(X),
+    _BE(X),
+    _BF(X),
+    _C0(X),
+    _C1(X),
+    _C2(X),
+    _C3(X),
+    _C4(X),
+    _C5(X),
+    _C6(X),
+    _C7(X),
+    _C8(X),
+    _C9(X),
+    _CA(X),
+    _CB(X),
+    _CC(X),
+    _CD(X),
+    _CE(X),
+    _CF(X),
+    _D0(X),
+    _D1(X),
+    _D2(X),
+    _D3(X),
+    _D4(X),
+    _D5(X),
+    _D6(X),
+    _D7(X),
+    _D8(X),
+    _D9(X),
+    _DA(X),
+    _DB(X),
+    _DC(X),
+    _DD(X),
+    _DE(X),
+    _DF(X),
+    _E0(X),
+    _E1(X),
+    _E2(X),
+    _E3(X),
+    _E4(X),
+    _E5(X),
+    _E6(X),
+    _E7(X),
+    _E8(X),
+    _E9(X),
+    _EA(X),
+    _EB(X),
+    _EC(X),
+    _ED(X),
+    _EE(X),
+    _EF(X),
+    _F0(X),
+    _F1(X),
+    _F2(X),
+    _F3(X),
+    _F4(X),
+    _F5(X),
+    _F6(X),
+    _F7(X),
+    _F8(X),
+    _F9(X),
+    _FA(X),
+    _FB(X),
+    _FC(X),
+    _FD(X),
+    _FE(X),
+    _FF(X),
 
     V3,
     V4,
 }
 
-fn check_niche_behavior () {
+fn check_niche_behavior() {
     if let E1::V2 { .. } = (E1::V1 { f: true }) {
         intrinsics::abort();
     }
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index 8481d9c39a3..e34b35d5c4a 100644
--- a/compiler/rustc_codegen_cranelift/example/std_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/std_example.rs
@@ -58,8 +58,9 @@ fn main() {
     assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7);
     assert_eq!(core::intrinsics::saturating_sub(0, -170141183460469231731687303715884105728i128), 170141183460469231731687303715884105727i128);
 
-    let _d = 0i128.checked_div(2i128);
-    let _d = 0u128.checked_div(2u128);
+    std::hint::black_box(std::hint::black_box(7571400400375753350092698930310845914i128) * 10);
+    assert!(0i128.checked_div(2i128).is_some());
+    assert!(0u128.checked_div(2u128).is_some());
     assert_eq!(1u128 + 2, 3);
 
     assert_eq!(0b100010000000000000000000000000000u128 >> 10, 0b10001000000000000000000u128);
diff --git a/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch b/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch
index d8775e2d022..eb452c5cd37 100644
--- a/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch
@@ -19,8 +19,8 @@ index 217899e..9cedeb7 100644
 +    // This is broken on x86_64-pc-windows-gnu presumably due to a broken powf implementation
 +    #[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)]
      fn value_stability() {
-         fn test_samples<F: Float + core::fmt::Debug, D: Distribution<F>>(
-             distr: D, zero: F, expected: &[F],
+         fn test_samples<F: Float + Debug + Display + LowerExp, D: Distribution<F>>(
+             distr: D, thresh: F, expected: &[F],
 diff --git a/rand_distr/tests/value_stability.rs b/rand_distr/tests/value_stability.rs
 index 192ba74..0101ace 100644
 --- a/rand_distr/tests/value_stability.rs
diff --git a/compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
index 865aa833a5e..6afa5c71fe5 100644
--- a/compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
@@ -13,14 +13,14 @@ Subject: [PATCH] [core] Disable not compiling tests
  6 files changed, 16 insertions(+), 1 deletion(-)
  create mode 100644 library/core/tests/Cargo.toml
 
-diff --git a/library/core/tests/Cargo.toml b/library/core/tests/Cargo.toml
+diff --git a/Cargo.toml b/Cargo.toml
 new file mode 100644
 index 0000000..46fd999
 --- /dev/null
-+++ b/library/core/tests/Cargo.toml
++++ b/Cargo.toml
 @@ -0,0 +1,12 @@
 +[package]
-+name = "core"
++name = "coretests"
 +version = "0.0.0"
 +edition = "2021"
 +
@@ -31,5 +31,14 @@ index 0000000..46fd999
 +[dependencies]
 +rand = { version = "0.8.5", default-features = false }
 +rand_xorshift = { version = "0.3.0", default-features = false }
+diff --git a/lib.rs b/lib.rs
+index 42a26ae..5ac1042 100644
+--- a/lib.rs
++++ b/lib.rs
+@@ -1,3 +1,4 @@
++#![cfg(test)]
+ #![feature(alloc_layout_extra)]
+ #![feature(array_chunks)]
+ #![feature(array_methods)]
 --
 2.21.0 (Apple Git-122)
diff --git a/compiler/rustc_codegen_cranelift/patches/0023-sysroot-Ignore-failing-tests.patch b/compiler/rustc_codegen_cranelift/patches/0023-coretests-Ignore-failing-tests.patch
index f3cd7ee77e2..f2cb82751f0 100644
--- a/compiler/rustc_codegen_cranelift/patches/0023-sysroot-Ignore-failing-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0023-coretests-Ignore-failing-tests.patch
@@ -10,10 +10,10 @@ Subject: [PATCH] [core] Ignore failing tests
  library/core/tests/time.rs       |  1 +
  4 files changed, 18 insertions(+), 2 deletions(-)
 
-diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
+diff --git a/array.rs b/array.rs
 index 4bc44e9..8e3c7a4 100644
---- a/library/core/tests/array.rs
-+++ b/library/core/tests/array.rs
+--- a/array.rs
++++ b/array.rs
 @@ -242,6 +242,7 @@ fn iterator_drops() {
      assert_eq!(i.get(), 5);
  }
@@ -46,10 +46,10 @@ index 4bc44e9..8e3c7a4 100644
  
  #[test]
  fn cell_allows_array_cycle() {
-diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
+diff --git a/atomic.rs b/atomic.rs
 index 13b12db..96fe4b9 100644
---- a/library/core/tests/atomic.rs
-+++ b/library/core/tests/atomic.rs
+--- a/atomic.rs
++++ b/atomic.rs
 @@ -185,6 +185,7 @@ fn ptr_bitops() {
  }
  
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
new file mode 100644
index 00000000000..1d5479bedde
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
@@ -0,0 +1,30 @@
+From ad7ffe71baba46865f2e65266ab025920dfdc20b Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Thu, 18 Feb 2021 18:45:28 +0100
+Subject: [PATCH] Disable 128bit atomic operations
+
+Cranelift doesn't support them yet
+---
+ library/core/src/panic/unwind_safe.rs |  6 -----
+ library/core/src/sync/atomic.rs       | 38 ---------------------------
+ library/core/tests/atomic.rs          |  4 ---
+ 4 files changed, 4 insertions(+), 50 deletions(-)
+
+diff --git a/atomic.rs b/atomic.rs
+index b735957..ea728b6 100644
+--- a/atomic.rs
++++ b/atomic.rs
+@@ -185,10 +185,6 @@ fn atomic_alignment() {
+     assert_eq!(align_of::<AtomicU64>(), size_of::<AtomicU64>());
+     #[cfg(target_has_atomic = "64")]
+     assert_eq!(align_of::<AtomicI64>(), size_of::<AtomicI64>());
+-    #[cfg(target_has_atomic = "128")]
+-    assert_eq!(align_of::<AtomicU128>(), size_of::<AtomicU128>());
+-    #[cfg(target_has_atomic = "128")]
+-    assert_eq!(align_of::<AtomicI128>(), size_of::<AtomicI128>());
+     #[cfg(target_has_atomic = "ptr")]
+     assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
+     #[cfg(target_has_atomic = "ptr")]
+--
+2.26.2.7.g19db9cfb68
+
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
index 77f437974c2..45f73f36b93 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
@@ -85,21 +85,6 @@ index d9de37e..8293fce 100644
  
  macro_rules! atomic_int_ptr_sized {
      ( $($target_pointer_width:literal $align:literal)* ) => { $(
-diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
-index b735957..ea728b6 100644
---- a/library/core/tests/atomic.rs
-+++ b/library/core/tests/atomic.rs
-@@ -185,10 +185,6 @@ fn atomic_alignment() {
-     assert_eq!(align_of::<AtomicU64>(), size_of::<AtomicU64>());
-     #[cfg(target_has_atomic = "64")]
-     assert_eq!(align_of::<AtomicI64>(), size_of::<AtomicI64>());
--    #[cfg(target_has_atomic = "128")]
--    assert_eq!(align_of::<AtomicU128>(), size_of::<AtomicU128>());
--    #[cfg(target_has_atomic = "128")]
--    assert_eq!(align_of::<AtomicI128>(), size_of::<AtomicI128>());
-     #[cfg(target_has_atomic = "ptr")]
-     assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
-     #[cfg(target_has_atomic = "ptr")]
 --
 2.26.2.7.g19db9cfb68
 
diff --git a/compiler/rustc_codegen_cranelift/patches/0028-sysroot-Disable-long-running-tests.patch b/compiler/rustc_codegen_cranelift/patches/0028-coretests-Disable-long-running-tests.patch
index d804a78cc10..440177018f4 100644
--- a/compiler/rustc_codegen_cranelift/patches/0028-sysroot-Disable-long-running-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0028-coretests-Disable-long-running-tests.patch
@@ -7,10 +7,10 @@ Subject: [PATCH] Disable long running tests
  library/core/tests/slice.rs | 2 ++
  1 file changed, 2 insertions(+)
 
-diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
+diff --git a/slice.rs b/slice.rs
 index 8402833..84592e0 100644
---- a/library/core/tests/slice.rs
-+++ b/library/core/tests/slice.rs
+--- a/slice.rs
++++ b/slice.rs
 @@ -1809,6 +1809,7 @@ fn sort_unstable() {
      assert!(v == [0xDEADBEEF]);
  }
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 40fb54b9159..2236a6ca155 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-02-06"
+channel = "nightly-2023-03-15"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
index c993430b830..939a1f1ca59 100644
--- a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
@@ -1,11 +1,14 @@
 use std::env;
 #[cfg(unix)]
 use std::os::unix::process::CommandExt;
-use std::path::PathBuf;
 use std::process::Command;
 
 fn main() {
-    let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
+    let current_exe = env::current_exe().unwrap();
+    let mut sysroot = current_exe.parent().unwrap();
+    if sysroot.file_name().unwrap().to_str().unwrap() == "bin" {
+        sysroot = sysroot.parent().unwrap();
+    }
 
     let mut rustflags = String::new();
     rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests -Zcodegen-backend=");
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
index c187f54a60e..b9bba7f2e08 100644
--- a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
@@ -2,11 +2,14 @@ use std::env;
 use std::ffi::OsString;
 #[cfg(unix)]
 use std::os::unix::process::CommandExt;
-use std::path::PathBuf;
 use std::process::Command;
 
 fn main() {
-    let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
+    let current_exe = env::current_exe().unwrap();
+    let mut sysroot = current_exe.parent().unwrap();
+    if sysroot.file_name().unwrap().to_str().unwrap() == "bin" {
+        sysroot = sysroot.parent().unwrap();
+    }
 
     let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
         env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
index a6528ac41ae..167631eaf7e 100644
--- a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
@@ -2,11 +2,14 @@ use std::env;
 use std::ffi::OsString;
 #[cfg(unix)]
 use std::os::unix::process::CommandExt;
-use std::path::PathBuf;
 use std::process::Command;
 
 fn main() {
-    let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
+    let current_exe = env::current_exe().unwrap();
+    let mut sysroot = current_exe.parent().unwrap();
+    if sysroot.file_name().unwrap().to_str().unwrap() == "bin" {
+        sysroot = sysroot.parent().unwrap();
+    }
 
     let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
         env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustup.sh b/compiler/rustc_codegen_cranelift/scripts/rustup.sh
index 34e3981b538..3cbeb6375de 100755
--- a/compiler/rustc_codegen_cranelift/scripts/rustup.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/rustup.sh
@@ -2,10 +2,24 @@
 
 set -e
 
+TOOLCHAIN=${TOOLCHAIN:-$(date +%Y-%m-%d)}
+
+function check_git_fixed_subtree() {
+    if [[ ! -e ./git-fixed-subtree.sh ]]; then
+        echo "Missing git-fixed-subtree.sh. Please run the following commands to download it:"
+        echo "curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/bjorn3/git/tqc-subtree-portable/contrib/subtree/git-subtree.sh -o git-fixed-subtree.sh"
+        echo "chmod u+x git-fixed-subtree.sh"
+        exit 1
+    fi
+    if [[ ! -x ./git-fixed-subtree.sh ]]; then
+        echo "git-fixed-subtree.sh is not executable. Please run the following command to make it executable:"
+        echo "chmod u+x git-fixed-subtree.sh"
+        exit 1
+    fi
+}
+
 case $1 in
     "prepare")
-        TOOLCHAIN=$(date +%Y-%m-%d)
-
         echo "=> Installing new nightly"
         rustup toolchain install --profile minimal "nightly-${TOOLCHAIN}" # Sanity check to see if the nightly exists
         sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain
@@ -27,28 +41,35 @@ case $1 in
         git commit -m "Rustup to $(rustc -V)"
         ;;
     "push")
+        check_git_fixed_subtree
+
         cg_clif=$(pwd)
         pushd ../rust
         git pull origin master
         branch=sync_cg_clif-$(date +%Y-%m-%d)
         git checkout -b "$branch"
-        git subtree pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/bjorn3/rustc_codegen_cranelift.git master
+        "$cg_clif/git-fixed-subtree.sh" pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/bjorn3/rustc_codegen_cranelift.git master
         git push -u my "$branch"
 
         # immediately merge the merge commit into cg_clif to prevent merge conflicts when syncing
         # from rust-lang/rust later
-        git subtree push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust
+        "$cg_clif/git-fixed-subtree.sh" push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust
         popd
         git merge sync_from_rust
 	;;
     "pull")
+        check_git_fixed_subtree
+
+        RUST_VERS=$(curl "https://static.rust-lang.org/dist/$TOOLCHAIN/channel-rust-nightly-git-commit-hash.txt")
+        echo "Pulling $RUST_VERS ($TOOLCHAIN)"
+
         cg_clif=$(pwd)
         pushd ../rust
-        git pull origin master
-        rust_vers="$(git rev-parse HEAD)"
-        git subtree push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust
+        git fetch origin master
+        git checkout "$RUST_VERS"
+        "$cg_clif/git-fixed-subtree.sh" push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust
         popd
-        git merge sync_from_rust -m "Sync from rust $rust_vers"
+        git merge sync_from_rust -m "Sync from rust $RUST_VERS"
         git branch -d sync_from_rust
         ;;
     *)
diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
index a08e80dd19a..abb09775d21 100644
--- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
@@ -10,7 +10,7 @@ git fetch
 git checkout -- .
 git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')"
 
-git -c user.name=Dummy -c user.email=dummy@example.com am ../patches/*-sysroot-*.patch
+git -c user.name=Dummy -c user.email=dummy@example.com am ../patches/*-stdlib-*.patch
 
 git apply - <<EOF
 diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
@@ -36,7 +36,7 @@ changelog-seen = 2
 ninja = false
 
 [build]
-rustc = "$(pwd)/../dist/rustc-clif"
+rustc = "$(pwd)/../dist/bin/rustc-clif"
 cargo = "$(rustup which cargo)"
 full-bootstrap = true
 local-rebuild = true
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index e14a129dbc2..20dcb4cf34d 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -21,6 +21,7 @@ done
 
 git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
 git checkout -- tests/ui/proc-macro/pretty-print-hack/
+rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR
 
 # missing features
 # ================
@@ -80,6 +81,7 @@ rm tests/ui/layout/valid_range_oob.rs # different ICE message
 
 rm tests/ui/consts/issue-miri-1910.rs # different error message
 rm tests/ui/consts/offset_ub.rs # same
+rm tests/ui/consts/const-eval/ub-slice-get-unchecked.rs # same
 rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # same
 rm tests/ui/lint/lint-const-item-mutation.rs # same
 rm tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs # same
@@ -110,12 +112,9 @@ rm tests/incremental/spike-neg2.rs # same
 
 rm tests/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
 
-rm tests/ui/simd/intrinsic/generic-as.rs # crash when accessing vector type filed (#1318)
+rm tests/ui/simd/intrinsic/generic-as.rs # crash when accessing vector type field (#1318)
 rm tests/ui/simd/simd-bitmask.rs # crash
 
-rm tests/ui/dyn-star/dyn-star-to-dyn.rs
-rm tests/ui/dyn-star/dispatch-on-pin-mut.rs
-
 # bugs in the test suite
 # ======================
 rm tests/ui/backtrace.rs # TODO warning
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 74396a66f54..3bc64c44524 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -4,6 +4,8 @@ mod comments;
 mod pass_mode;
 mod returning;
 
+use std::borrow::Cow;
+
 use cranelift_module::ModuleError;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::layout::FnAbiOf;
@@ -25,7 +27,7 @@ fn clif_sig_from_fn_abi<'tcx>(
 ) -> Signature {
     let call_conv = conv_to_call_conv(tcx.sess, fn_abi.conv, default_call_conv);
 
-    let inputs = fn_abi.args.iter().map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()).flatten();
+    let inputs = fn_abi.args.iter().flat_map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter());
 
     let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx);
     // Sometimes the first param is an pointer to the place where the return value needs to be stored.
@@ -116,7 +118,52 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
         params: Vec<AbiParam>,
         returns: Vec<AbiParam>,
         args: &[Value],
-    ) -> &[Value] {
+    ) -> Cow<'_, [Value]> {
+        if self.tcx.sess.target.is_like_windows {
+            let (mut params, mut args): (Vec<_>, Vec<_>) =
+                params
+                    .into_iter()
+                    .zip(args)
+                    .map(|(param, &arg)| {
+                        if param.value_type == types::I128 {
+                            let arg_ptr = Pointer::stack_slot(self.bcx.create_sized_stack_slot(
+                                StackSlotData { kind: StackSlotKind::ExplicitSlot, size: 16 },
+                            ));
+                            arg_ptr.store(self, arg, MemFlags::trusted());
+                            (AbiParam::new(self.pointer_type), arg_ptr.get_addr(self))
+                        } else {
+                            (param, arg)
+                        }
+                    })
+                    .unzip();
+
+            let indirect_ret_val = returns.len() == 1 && returns[0].value_type == types::I128;
+
+            if indirect_ret_val {
+                params.insert(0, AbiParam::new(self.pointer_type));
+                let ret_ptr =
+                    Pointer::stack_slot(self.bcx.create_sized_stack_slot(StackSlotData {
+                        kind: StackSlotKind::ExplicitSlot,
+                        size: 16,
+                    }));
+                args.insert(0, ret_ptr.get_addr(self));
+                self.lib_call_unadjusted(name, params, vec![], &args);
+                return Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())]);
+            } else {
+                return self.lib_call_unadjusted(name, params, returns, &args);
+            }
+        }
+
+        self.lib_call_unadjusted(name, params, returns, args)
+    }
+
+    pub(crate) fn lib_call_unadjusted(
+        &mut self,
+        name: &str,
+        params: Vec<AbiParam>,
+        returns: Vec<AbiParam>,
+        args: &[Value],
+    ) -> Cow<'_, [Value]> {
         let sig = Signature { params, returns, call_conv: self.target_config.default_call_conv };
         let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap();
         let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
@@ -125,41 +172,11 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
         }
         let call_inst = self.bcx.ins().call(func_ref, args);
         if self.clif_comments.enabled() {
-            self.add_comment(call_inst, format!("easy_call {}", name));
+            self.add_comment(call_inst, format!("lib_call {}", name));
         }
         let results = self.bcx.inst_results(call_inst);
         assert!(results.len() <= 2, "{}", results.len());
-        results
-    }
-
-    pub(crate) fn easy_call(
-        &mut self,
-        name: &str,
-        args: &[CValue<'tcx>],
-        return_ty: Ty<'tcx>,
-    ) -> CValue<'tcx> {
-        let (input_tys, args): (Vec<_>, Vec<_>) = args
-            .iter()
-            .map(|arg| {
-                (AbiParam::new(self.clif_type(arg.layout().ty).unwrap()), arg.load_scalar(self))
-            })
-            .unzip();
-        let return_layout = self.layout_of(return_ty);
-        let return_tys = if let ty::Tuple(tup) = return_ty.kind() {
-            tup.iter().map(|ty| AbiParam::new(self.clif_type(ty).unwrap())).collect()
-        } else {
-            vec![AbiParam::new(self.clif_type(return_ty).unwrap())]
-        };
-        let ret_vals = self.lib_call(name, input_tys, return_tys, &args);
-        match *ret_vals {
-            [] => CValue::by_ref(
-                Pointer::const_addr(self, i64::from(self.pointer_type.bytes())),
-                return_layout,
-            ),
-            [val] => CValue::by_val(val, return_layout),
-            [val, extra] => CValue::by_val_pair(val, extra, return_layout),
-            _ => unreachable!(),
-        }
+        Cow::Borrowed(results)
     }
 }
 
@@ -275,10 +292,6 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
     self::comments::add_locals_header_comment(fx);
 
     for (local, arg_kind, ty) in func_params {
-        let layout = fx.layout_of(ty);
-
-        let is_ssa = ssa_analyzed[local] == crate::analyze::SsaKind::Ssa;
-
         // While this is normally an optimization to prevent an unnecessary copy when an argument is
         // not mutated by the current function, this is necessary to support unsized arguments.
         if let ArgKind::Normal(Some(val)) = arg_kind {
@@ -300,6 +313,8 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
             }
         }
 
+        let layout = fx.layout_of(ty);
+        let is_ssa = ssa_analyzed[local].is_ssa(fx, ty);
         let place = make_local_place(fx, local, layout, is_ssa);
         assert_eq!(fx.local_map.push(place), local);
 
@@ -323,7 +338,7 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
         let ty = fx.monomorphize(fx.mir.local_decls[local].ty);
         let layout = fx.layout_of(ty);
 
-        let is_ssa = ssa_analyzed[local] == crate::analyze::SsaKind::Ssa;
+        let is_ssa = ssa_analyzed[local].is_ssa(fx, ty);
 
         let place = make_local_place(fx, local, layout, is_ssa);
         assert_eq!(fx.local_map.push(place), local);
@@ -515,10 +530,9 @@ pub(crate) fn codegen_terminator_call<'tcx>(
                 args.into_iter()
                     .enumerate()
                     .skip(if first_arg_override.is_some() { 1 } else { 0 })
-                    .map(|(i, arg)| {
+                    .flat_map(|(i, arg)| {
                         adjust_arg_for_abi(fx, arg.value, &fn_abi.args[i], arg.is_owned).into_iter()
-                    })
-                    .flatten(),
+                    }),
             )
             .collect::<Vec<Value>>();
 
diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
index aaa1418767a..6d3e8eda276 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
@@ -14,7 +14,8 @@ pub(super) fn codegen_return_param<'tcx>(
 ) -> CPlace<'tcx> {
     let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
         PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => {
-            let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa;
+            let is_ssa =
+                ssa_analyzed[RETURN_PLACE].is_ssa(fx, fx.fn_abi.as_ref().unwrap().ret.layout.ty);
             (
                 super::make_local_place(
                     fx,
diff --git a/compiler/rustc_codegen_cranelift/src/analyze.rs b/compiler/rustc_codegen_cranelift/src/analyze.rs
index 0cbb9f3ec2d..54d5c1c2ae9 100644
--- a/compiler/rustc_codegen_cranelift/src/analyze.rs
+++ b/compiler/rustc_codegen_cranelift/src/analyze.rs
@@ -4,34 +4,30 @@ use crate::prelude::*;
 
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::StatementKind::*;
+use rustc_middle::ty::Ty;
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub(crate) enum SsaKind {
     NotSsa,
-    Ssa,
+    MaybeSsa,
+}
+
+impl SsaKind {
+    pub(crate) fn is_ssa<'tcx>(self, fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
+        self == SsaKind::MaybeSsa && (fx.clif_type(ty).is_some() || fx.clif_pair_type(ty).is_some())
+    }
 }
 
 pub(crate) fn analyze(fx: &FunctionCx<'_, '_, '_>) -> IndexVec<Local, SsaKind> {
-    let mut flag_map = fx
-        .mir
-        .local_decls
-        .iter()
-        .map(|local_decl| {
-            let ty = fx.monomorphize(local_decl.ty);
-            if fx.clif_type(ty).is_some() || fx.clif_pair_type(ty).is_some() {
-                SsaKind::Ssa
-            } else {
-                SsaKind::NotSsa
-            }
-        })
-        .collect::<IndexVec<Local, SsaKind>>();
+    let mut flag_map =
+        fx.mir.local_decls.iter().map(|_| SsaKind::MaybeSsa).collect::<IndexVec<Local, SsaKind>>();
 
     for bb in fx.mir.basic_blocks.iter() {
         for stmt in bb.statements.iter() {
             match &stmt.kind {
                 Assign(place_and_rval) => match &place_and_rval.1 {
                     Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
-                        not_ssa(&mut flag_map, place.local)
+                        flag_map[place.local] = SsaKind::NotSsa;
                     }
                     _ => {}
                 },
@@ -42,7 +38,3 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, '_>) -> IndexVec<Local, SsaKind> {
 
     flag_map
 }
-
-fn not_ssa(flag_map: &mut IndexVec<Local, SsaKind>, local: Local) {
-    flag_map[local] = SsaKind::NotSsa;
-}
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 230256ba5aa..1b8e9312e2f 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -192,7 +192,7 @@ pub(crate) fn compile_fn(
                         let pass_times = cranelift_codegen::timing::take_current();
                         // Replace newlines with | as measureme doesn't allow control characters like
                         // newlines inside strings.
-                        recorder.record_arg(format!("{}", pass_times).replace("\n", " | "));
+                        recorder.record_arg(format!("{}", pass_times).replace('\n', " | "));
                         recording_args = true;
                     },
                 )
@@ -346,17 +346,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                 crate::abi::codegen_return(fx);
             }
             TerminatorKind::Assert { cond, expected, msg, target, cleanup: _ } => {
-                if !fx.tcx.sess.overflow_checks() {
-                    let overflow_not_to_check = match msg {
-                        AssertKind::OverflowNeg(..) => true,
-                        AssertKind::Overflow(op, ..) => op.is_checkable(),
-                        _ => false,
-                    };
-                    if overflow_not_to_check {
-                        let target = fx.get_block(*target);
-                        fx.bcx.ins().jump(target, &[]);
-                        continue;
-                    }
+                if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() {
+                    let target = fx.get_block(*target);
+                    fx.bcx.ins().jump(target, &[]);
+                    continue;
                 }
                 let cond = codegen_operand(fx, cond).load_scalar(fx);
 
@@ -365,11 +358,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                 fx.bcx.set_cold_block(failure);
 
                 if *expected {
-                    fx.bcx.ins().brz(cond, failure, &[]);
+                    fx.bcx.ins().brif(cond, target, &[], failure, &[]);
                 } else {
-                    fx.bcx.ins().brnz(cond, failure, &[]);
+                    fx.bcx.ins().brif(cond, failure, &[], target, &[]);
                 };
-                fx.bcx.ins().jump(target, &[]);
 
                 fx.bcx.switch_to_block(failure);
                 fx.bcx.ins().nop();
@@ -425,11 +417,9 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                         }
                     } else {
                         if test_zero {
-                            fx.bcx.ins().brz(discr, then_block, &[]);
-                            fx.bcx.ins().jump(else_block, &[]);
+                            fx.bcx.ins().brif(discr, else_block, &[], then_block, &[]);
                         } else {
-                            fx.bcx.ins().brnz(discr, then_block, &[]);
-                            fx.bcx.ins().jump(else_block, &[]);
+                            fx.bcx.ins().brif(discr, then_block, &[], else_block, &[]);
                         }
                     }
                 } else {
@@ -750,8 +740,7 @@ fn codegen_stmt<'tcx>(
 
                         fx.bcx.switch_to_block(loop_block);
                         let done = fx.bcx.ins().icmp_imm(IntCC::Equal, index, times as i64);
-                        fx.bcx.ins().brnz(done, done_block, &[]);
-                        fx.bcx.ins().jump(loop_block2, &[]);
+                        fx.bcx.ins().brif(done, done_block, &[], loop_block2, &[]);
 
                         fx.bcx.switch_to_block(loop_block2);
                         let to = lval.place_index(fx, index);
@@ -997,7 +986,7 @@ fn codegen_panic_inner<'tcx>(
     let symbol_name = fx.tcx.symbol_name(instance).name;
 
     fx.lib_call(
-        &*symbol_name,
+        symbol_name,
         args.iter().map(|&arg| AbiParam::new(fx.bcx.func.dfg.value_type(arg))).collect(),
         vec![],
         args,
diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs
index 5091c5a9fed..032d1151041 100644
--- a/compiler/rustc_codegen_cranelift/src/cast.rs
+++ b/compiler/rustc_codegen_cranelift/src/cast.rs
@@ -64,17 +64,12 @@ pub(crate) fn clif_int_or_float_cast(
                 },
             );
 
-            let from_rust_ty = if from_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
-
-            let to_rust_ty = match to_ty {
-                types::F32 => fx.tcx.types.f32,
-                types::F64 => fx.tcx.types.f64,
-                _ => unreachable!(),
-            };
-
-            return fx
-                .easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty)
-                .load_scalar(fx);
+            return fx.lib_call(
+                &name,
+                vec![AbiParam::new(types::I128)],
+                vec![AbiParam::new(to_ty)],
+                &[from],
+            )[0];
         }
 
         // int-like -> float
@@ -101,16 +96,29 @@ pub(crate) fn clif_int_or_float_cast(
                 },
             );
 
-            let from_rust_ty = match from_ty {
-                types::F32 => fx.tcx.types.f32,
-                types::F64 => fx.tcx.types.f64,
-                _ => unreachable!(),
-            };
-
-            let to_rust_ty = if to_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
-
-            fx.easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty)
-                .load_scalar(fx)
+            if fx.tcx.sess.target.is_like_windows {
+                let ret = fx.lib_call(
+                    &name,
+                    vec![AbiParam::new(from_ty)],
+                    vec![AbiParam::new(types::I64X2)],
+                    &[from],
+                )[0];
+                // FIXME use bitcast instead of store to get from i64x2 to i128
+                let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
+                    kind: StackSlotKind::ExplicitSlot,
+                    size: 16,
+                });
+                let ret_ptr = Pointer::stack_slot(stack_slot);
+                ret_ptr.store(fx, ret, MemFlags::trusted());
+                ret_ptr.load(fx, types::I128, MemFlags::trusted())
+            } else {
+                fx.lib_call(
+                    &name,
+                    vec![AbiParam::new(from_ty)],
+                    vec![AbiParam::new(types::I128)],
+                    &[from],
+                )[0]
+            }
         } else if to_ty == types::I8 || to_ty == types::I16 {
             // FIXME implement fcvt_to_*int_sat.i8/i16
             let val = if to_signed {
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index 40bfe70771c..f674ce776a6 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -29,39 +29,24 @@ pub(crate) fn maybe_codegen<'tcx>(
         BinOp::Add | BinOp::Sub if !checked => None,
         BinOp::Mul if !checked || is_signed => {
             if !checked {
-                let val_ty = if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
-                if fx.tcx.sess.target.is_like_windows {
-                    let ret_place = CPlace::new_stack_slot(fx, lhs.layout());
-                    let (lhs_ptr, lhs_extra) = lhs.force_stack(fx);
-                    let (rhs_ptr, rhs_extra) = rhs.force_stack(fx);
-                    assert!(lhs_extra.is_none());
-                    assert!(rhs_extra.is_none());
-                    let args = [
-                        ret_place.to_ptr().get_addr(fx),
-                        lhs_ptr.get_addr(fx),
-                        rhs_ptr.get_addr(fx),
-                    ];
-                    fx.lib_call(
-                        "__multi3",
-                        vec![
-                            AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
-                            AbiParam::new(fx.pointer_type),
-                            AbiParam::new(fx.pointer_type),
-                        ],
-                        vec![],
-                        &args,
-                    );
-                    Some(ret_place.to_cvalue(fx))
-                } else {
-                    Some(fx.easy_call("__multi3", &[lhs, rhs], val_ty))
-                }
+                let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
+                let ret_val = fx.lib_call(
+                    "__multi3",
+                    vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
+                    vec![AbiParam::new(types::I128)],
+                    &args,
+                )[0];
+                Some(CValue::by_val(
+                    ret_val,
+                    fx.layout_of(if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }),
+                ))
             } else {
                 let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
                 let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
                 let lhs = lhs.load_scalar(fx);
                 let rhs = rhs.load_scalar(fx);
                 let oflow_ptr = oflow.to_ptr().get_addr(fx);
-                let res = fx.lib_call(
+                let res = fx.lib_call_unadjusted(
                     "__muloti4",
                     vec![
                         AbiParam::new(types::I128),
@@ -80,29 +65,12 @@ pub(crate) fn maybe_codegen<'tcx>(
             assert!(checked);
             let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
             let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
-            let (param_types, args) = if fx.tcx.sess.target.is_like_windows {
-                let (lhs_ptr, lhs_extra) = lhs.force_stack(fx);
-                let (rhs_ptr, rhs_extra) = rhs.force_stack(fx);
-                assert!(lhs_extra.is_none());
-                assert!(rhs_extra.is_none());
-                (
-                    vec![
-                        AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
-                        AbiParam::new(fx.pointer_type),
-                        AbiParam::new(fx.pointer_type),
-                    ],
-                    [out_place.to_ptr().get_addr(fx), lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)],
-                )
-            } else {
-                (
-                    vec![
-                        AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
-                        AbiParam::new(types::I128),
-                        AbiParam::new(types::I128),
-                    ],
-                    [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)],
-                )
-            };
+            let param_types = vec![
+                AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
+                AbiParam::new(types::I128),
+                AbiParam::new(types::I128),
+            ];
+            let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
             let name = match (bin_op, is_signed) {
                 (BinOp::Add, false) => "__rust_u128_addo",
                 (BinOp::Add, true) => "__rust_i128_addo",
@@ -125,14 +93,10 @@ pub(crate) fn maybe_codegen<'tcx>(
                 _ => unreachable!(),
             };
             if fx.tcx.sess.target.is_like_windows {
-                let (lhs_ptr, lhs_extra) = lhs.force_stack(fx);
-                let (rhs_ptr, rhs_extra) = rhs.force_stack(fx);
-                assert!(lhs_extra.is_none());
-                assert!(rhs_extra.is_none());
-                let args = [lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)];
+                let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
                 let ret = fx.lib_call(
                     name,
-                    vec![AbiParam::new(fx.pointer_type), AbiParam::new(fx.pointer_type)],
+                    vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
                     vec![AbiParam::new(types::I64X2)],
                     &args,
                 )[0];
@@ -141,7 +105,14 @@ pub(crate) fn maybe_codegen<'tcx>(
                 ret_place.to_ptr().store(fx, ret, MemFlags::trusted());
                 Some(ret_place.to_cvalue(fx))
             } else {
-                Some(fx.easy_call(name, &[lhs, rhs], lhs.layout().ty))
+                let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
+                let ret_val = fx.lib_call(
+                    name,
+                    vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
+                    vec![AbiParam::new(types::I128)],
+                    &args,
+                )[0];
+                Some(CValue::by_val(ret_val, lhs.layout()))
             }
         }
         BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => {
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 722e2754e83..d39bf700035 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -75,7 +75,7 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<types::Typ
         ty::Adt(adt_def, _) if adt_def.repr().simd() => {
             let (element, count) = match &tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().abi
             {
-                Abi::Vector { element, count } => (element.clone(), *count),
+                Abi::Vector { element, count } => (*element, *count),
                 _ => unreachable!(),
             };
 
diff --git a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
index 8a53baa763a..f3b963200a0 100644
--- a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
+++ b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
@@ -39,6 +39,7 @@ builtin_functions! {
 
     // integers
     fn __multi3(a: i128, b: i128) -> i128;
+    fn __muloti4(n: i128, d: i128, oflow: &mut i32) -> i128;
     fn __udivti3(n: u128, d: u128) -> u128;
     fn __divti3(n: i128, d: i128) -> i128;
     fn __umodti3(n: u128, d: u128) -> u128;
diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
index f855e20e0a1..203219a8a75 100644
--- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
+++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
@@ -32,7 +32,7 @@ impl ConcurrencyLimiter {
         ConcurrencyLimiter {
             helper_thread: Some(helper_thread),
             state,
-            available_token_condvar: Arc::new(Condvar::new()),
+            available_token_condvar,
             finished: false,
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index efdf9f6d5bc..31278f810e9 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -290,7 +290,7 @@ fn data_id_for_static(
         };
 
         let data_id = match module.declare_data(
-            &*symbol_name,
+            symbol_name,
             linkage,
             is_mutable,
             attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
@@ -338,7 +338,7 @@ fn data_id_for_static(
     };
 
     let data_id = match module.declare_data(
-        &*symbol_name,
+        symbol_name,
         linkage,
         is_mutable,
         attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
diff --git a/compiler/rustc_codegen_cranelift/src/cranelift_native.rs b/compiler/rustc_codegen_cranelift/src/cranelift_native.rs
deleted file mode 100644
index 6c4efca4424..00000000000
--- a/compiler/rustc_codegen_cranelift/src/cranelift_native.rs
+++ /dev/null
@@ -1,248 +0,0 @@
-// Vendored from https://github.com/bytecodealliance/wasmtime/blob/b58a197d33f044193c3d608010f5e6ec394ac07e/cranelift/native/src/lib.rs
-// which is licensed as
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-// unlike rustc_codegen_cranelift itself. Also applies a small change to remove #![cfg_attr] that
-// rust's CI complains about and to fix formatting to match rustc.
-// FIXME revert back to the external crate with Cranelift 0.93
-#![allow(warnings)]
-
-//! Performs autodetection of the host for the purposes of running
-//! Cranelift to generate code to run on the same machine.
-
-#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates, unstable_features)]
-#![warn(unused_import_braces)]
-
-use cranelift_codegen::isa;
-use target_lexicon::Triple;
-
-/// Return an `isa` builder configured for the current host
-/// machine, or `Err(())` if the host machine is not supported
-/// in the current configuration.
-pub fn builder() -> Result<isa::Builder, &'static str> {
-    builder_with_options(true)
-}
-
-/// Return an `isa` builder configured for the current host
-/// machine, or `Err(())` if the host machine is not supported
-/// in the current configuration.
-///
-/// Selects the given backend variant specifically; this is
-/// useful when more than oen backend exists for a given target
-/// (e.g., on x86-64).
-pub fn builder_with_options(infer_native_flags: bool) -> Result<isa::Builder, &'static str> {
-    let mut isa_builder = isa::lookup(Triple::host()).map_err(|err| match err {
-        isa::LookupError::SupportDisabled => "support for architecture disabled at compile time",
-        isa::LookupError::Unsupported => "unsupported architecture",
-    })?;
-
-    #[cfg(target_arch = "x86_64")]
-    {
-        use cranelift_codegen::settings::Configurable;
-
-        if !std::is_x86_feature_detected!("sse2") {
-            return Err("x86 support requires SSE2");
-        }
-
-        if !infer_native_flags {
-            return Ok(isa_builder);
-        }
-
-        // These are temporarily enabled by default (see #3810 for
-        // more) so that a default-constructed `Flags` can work with
-        // default Wasmtime features. Otherwise, the user must
-        // explicitly use native flags or turn these on when on x86-64
-        // platforms to avoid a configuration panic. In order for the
-        // "enable if detected" logic below to work, we must turn them
-        // *off* (differing from the default) and then re-enable below
-        // if present.
-        isa_builder.set("has_sse3", "false").unwrap();
-        isa_builder.set("has_ssse3", "false").unwrap();
-        isa_builder.set("has_sse41", "false").unwrap();
-        isa_builder.set("has_sse42", "false").unwrap();
-
-        if std::is_x86_feature_detected!("sse3") {
-            isa_builder.enable("has_sse3").unwrap();
-        }
-        if std::is_x86_feature_detected!("ssse3") {
-            isa_builder.enable("has_ssse3").unwrap();
-        }
-        if std::is_x86_feature_detected!("sse4.1") {
-            isa_builder.enable("has_sse41").unwrap();
-        }
-        if std::is_x86_feature_detected!("sse4.2") {
-            isa_builder.enable("has_sse42").unwrap();
-        }
-        if std::is_x86_feature_detected!("popcnt") {
-            isa_builder.enable("has_popcnt").unwrap();
-        }
-        if std::is_x86_feature_detected!("avx") {
-            isa_builder.enable("has_avx").unwrap();
-        }
-        if std::is_x86_feature_detected!("avx2") {
-            isa_builder.enable("has_avx2").unwrap();
-        }
-        if std::is_x86_feature_detected!("fma") {
-            isa_builder.enable("has_fma").unwrap();
-        }
-        if std::is_x86_feature_detected!("bmi1") {
-            isa_builder.enable("has_bmi1").unwrap();
-        }
-        if std::is_x86_feature_detected!("bmi2") {
-            isa_builder.enable("has_bmi2").unwrap();
-        }
-        if std::is_x86_feature_detected!("avx512bitalg") {
-            isa_builder.enable("has_avx512bitalg").unwrap();
-        }
-        if std::is_x86_feature_detected!("avx512dq") {
-            isa_builder.enable("has_avx512dq").unwrap();
-        }
-        if std::is_x86_feature_detected!("avx512f") {
-            isa_builder.enable("has_avx512f").unwrap();
-        }
-        if std::is_x86_feature_detected!("avx512vl") {
-            isa_builder.enable("has_avx512vl").unwrap();
-        }
-        if std::is_x86_feature_detected!("avx512vbmi") {
-            isa_builder.enable("has_avx512vbmi").unwrap();
-        }
-        if std::is_x86_feature_detected!("lzcnt") {
-            isa_builder.enable("has_lzcnt").unwrap();
-        }
-    }
-
-    #[cfg(target_arch = "aarch64")]
-    {
-        use cranelift_codegen::settings::Configurable;
-
-        if !infer_native_flags {
-            return Ok(isa_builder);
-        }
-
-        if std::arch::is_aarch64_feature_detected!("lse") {
-            isa_builder.enable("has_lse").unwrap();
-        }
-
-        if std::arch::is_aarch64_feature_detected!("paca") {
-            isa_builder.enable("has_pauth").unwrap();
-        }
-
-        if cfg!(target_os = "macos") {
-            // Pointer authentication is always available on Apple Silicon.
-            isa_builder.enable("sign_return_address").unwrap();
-            // macOS enforces the use of the B key for return addresses.
-            isa_builder.enable("sign_return_address_with_bkey").unwrap();
-        }
-    }
-
-    // There is no is_s390x_feature_detected macro yet, so for now
-    // we use getauxval from the libc crate directly.
-    #[cfg(all(target_arch = "s390x", target_os = "linux"))]
-    {
-        use cranelift_codegen::settings::Configurable;
-
-        if !infer_native_flags {
-            return Ok(isa_builder);
-        }
-
-        let v = unsafe { libc::getauxval(libc::AT_HWCAP) };
-        const HWCAP_S390X_VXRS_EXT2: libc::c_ulong = 32768;
-        if (v & HWCAP_S390X_VXRS_EXT2) != 0 {
-            isa_builder.enable("has_vxrs_ext2").unwrap();
-            // There is no separate HWCAP bit for mie2, so assume
-            // that any machine with vxrs_ext2 also has mie2.
-            isa_builder.enable("has_mie2").unwrap();
-        }
-    }
-
-    // `is_riscv_feature_detected` is nightly only for now, use
-    // getauxval from the libc crate directly as a temporary measure.
-    #[cfg(all(target_arch = "riscv64", target_os = "linux"))]
-    {
-        use cranelift_codegen::settings::Configurable;
-
-        if !infer_native_flags {
-            return Ok(isa_builder);
-        }
-
-        let v = unsafe { libc::getauxval(libc::AT_HWCAP) };
-
-        const HWCAP_RISCV_EXT_A: libc::c_ulong = 1 << (b'a' - b'a');
-        const HWCAP_RISCV_EXT_C: libc::c_ulong = 1 << (b'c' - b'a');
-        const HWCAP_RISCV_EXT_D: libc::c_ulong = 1 << (b'd' - b'a');
-        const HWCAP_RISCV_EXT_F: libc::c_ulong = 1 << (b'f' - b'a');
-        const HWCAP_RISCV_EXT_M: libc::c_ulong = 1 << (b'm' - b'a');
-        const HWCAP_RISCV_EXT_V: libc::c_ulong = 1 << (b'v' - b'a');
-
-        if (v & HWCAP_RISCV_EXT_A) != 0 {
-            isa_builder.enable("has_a").unwrap();
-        }
-
-        if (v & HWCAP_RISCV_EXT_C) != 0 {
-            isa_builder.enable("has_c").unwrap();
-        }
-
-        if (v & HWCAP_RISCV_EXT_D) != 0 {
-            isa_builder.enable("has_d").unwrap();
-        }
-
-        if (v & HWCAP_RISCV_EXT_F) != 0 {
-            isa_builder.enable("has_f").unwrap();
-
-            // TODO: There doesn't seem to be a bit associated with this extension
-            // rust enables it with the `f` extension:
-            // https://github.com/rust-lang/stdarch/blob/790411f93c4b5eada3c23abb4c9a063fb0b24d99/crates/std_detect/src/detect/os/linux/riscv.rs#L43
-            isa_builder.enable("has_zicsr").unwrap();
-        }
-
-        if (v & HWCAP_RISCV_EXT_M) != 0 {
-            isa_builder.enable("has_m").unwrap();
-        }
-
-        if (v & HWCAP_RISCV_EXT_V) != 0 {
-            isa_builder.enable("has_v").unwrap();
-        }
-
-        // TODO: ZiFencei does not have a bit associated with it
-        // TODO: Zbkb does not have a bit associated with it
-    }
-
-    // squelch warnings about unused mut/variables on some platforms.
-    drop(&mut isa_builder);
-    drop(infer_native_flags);
-
-    Ok(isa_builder)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::builder;
-    use cranelift_codegen::isa::CallConv;
-    use cranelift_codegen::settings;
-
-    #[test]
-    fn test() {
-        if let Ok(isa_builder) = builder() {
-            let flag_builder = settings::builder();
-            let isa = isa_builder.finish(settings::Flags::new(flag_builder)).unwrap();
-
-            if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
-                assert_eq!(isa.default_call_conv(), CallConv::AppleAarch64);
-            } else if cfg!(any(unix, target_os = "nebulet")) {
-                assert_eq!(isa.default_call_conv(), CallConv::SystemV);
-            } else if cfg!(windows) {
-                assert_eq!(isa.default_call_conv(), CallConv::WindowsFastcall);
-            }
-
-            if cfg!(target_pointer_width = "64") {
-                assert_eq!(isa.pointer_bits(), 64);
-            } else if cfg!(target_pointer_width = "32") {
-                assert_eq!(isa.pointer_bits(), 32);
-            } else if cfg!(target_pointer_width = "16") {
-                assert_eq!(isa.pointer_bits(), 16);
-            }
-        }
-    }
-}
-
-/// Version number of this crate.
-pub const VERSION: &str = env!("CARGO_PKG_VERSION");
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
index 9583cd2ec60..c4a5627e662 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
@@ -113,7 +113,7 @@ impl Writer for WriterRelocate {
                     offset: offset as u32,
                     size,
                     name: DebugRelocName::Symbol(symbol),
-                    addend: addend as i64,
+                    addend,
                     kind: object::RelocationKind::Absolute,
                 });
                 self.write_udata(0, size)
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 7c6fd9f6f1e..3e2e2af9688 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -377,7 +377,7 @@ pub(crate) fn run_aot(
     };
 
     if tcx.dep_graph.is_fully_enabled() {
-        for cgu in &*cgus {
+        for cgu in cgus {
             tcx.ensure().codegen_unit(cgu.name());
         }
     }
@@ -417,7 +417,7 @@ pub(crate) fn run_aot(
                     CguReuse::PreLto => unreachable!(),
                     CguReuse::PostLto => {
                         concurrency_limiter.job_already_done();
-                        OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, &*cgu))
+                        OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))
                     }
                 }
             })
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index 8b5a2da2c59..f6a48e3257b 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -311,7 +311,11 @@ fn dep_symbol_lookup_fn(
         .find(|(crate_type, _data)| *crate_type == rustc_session::config::CrateType::Executable)
         .unwrap()
         .1;
-    for &cnum in &crate_info.used_crates {
+    // `used_crates` is in reverse postorder in terms of dependencies. Reverse the order here to
+    // get a postorder which ensures that all dependencies of a dylib are loaded before the dylib
+    // itself. This helps the dynamic linker to find dylibs not in the regular dynamic library
+    // search path.
+    for &cnum in crate_info.used_crates.iter().rev() {
         let src = &crate_info.used_crate_source[&cnum];
         match data[cnum.as_usize() - 1] {
             Linkage::NotLinked | Linkage::IncludedFromDylib => {}
diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs
index 46c78ce6a1e..a74f8ffa23d 100644
--- a/compiler/rustc_codegen_cranelift/src/global_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs
@@ -125,7 +125,7 @@ pub(crate) fn compile_global_asm(
     let output_object_file = config.output_filenames.temp_path(OutputType::Object, Some(cgu_name));
 
     // Assemble `global_asm`
-    let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm");
+    let global_asm_object_file = add_file_stem_postfix(output_object_file, ".asm");
     let mut child = Command::new(&config.assembler)
         .arg("-o")
         .arg(&global_asm_object_file)
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 6206fbf7dd5..3ba530c040f 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -242,7 +242,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
                 }
             }
             InlineAsmOperand::Const { ref value } => {
-                let (const_value, ty) = crate::constant::eval_mir_constant(fx, &*value)
+                let (const_value, ty) = crate::constant::eval_mir_constant(fx, value)
                     .unwrap_or_else(|| span_bug!(span, "asm const cannot be resolved"));
                 let value = rustc_codegen_ssa::common::asm_const_to_str(
                     fx.tcx,
@@ -334,13 +334,13 @@ pub(crate) fn codegen_inline_asm<'tcx>(
             }
             CInlineAsmOperand::Out { reg: _, late: _, place } => {
                 if let Some(place) = place {
-                    outputs.push((asm_gen.stack_slots_output[i].unwrap(), place.clone()));
+                    outputs.push((asm_gen.stack_slots_output[i].unwrap(), *place));
                 }
             }
             CInlineAsmOperand::InOut { reg: _, _late: _, in_value, out_place } => {
                 inputs.push((asm_gen.stack_slots_input[i].unwrap(), in_value.load_scalar(fx)));
                 if let Some(out_place) = out_place {
-                    outputs.push((asm_gen.stack_slots_output[i].unwrap(), out_place.clone()));
+                    outputs.push((asm_gen.stack_slots_output[i].unwrap(), *out_place));
                 }
             }
             CInlineAsmOperand::Const { value: _ } | CInlineAsmOperand::Symbol { symbol: _ } => {}
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 24f8d5e464e..fe48cac4faf 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -23,7 +23,7 @@ pub(crate) use llvm::codegen_llvm_intrinsic_call;
 
 use rustc_middle::ty;
 use rustc_middle::ty::layout::{HasParamEnv, ValidityRequirement};
-use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_span::symbol::{kw, sym, Symbol};
 
@@ -252,45 +252,45 @@ fn codegen_float_intrinsic_call<'tcx>(
     args: &[mir::Operand<'tcx>],
     ret: CPlace<'tcx>,
 ) -> bool {
-    let (name, arg_count, ty) = match intrinsic {
-        sym::expf32 => ("expf", 1, fx.tcx.types.f32),
-        sym::expf64 => ("exp", 1, fx.tcx.types.f64),
-        sym::exp2f32 => ("exp2f", 1, fx.tcx.types.f32),
-        sym::exp2f64 => ("exp2", 1, fx.tcx.types.f64),
-        sym::sqrtf32 => ("sqrtf", 1, fx.tcx.types.f32),
-        sym::sqrtf64 => ("sqrt", 1, fx.tcx.types.f64),
-        sym::powif32 => ("__powisf2", 2, fx.tcx.types.f32), // compiler-builtins
-        sym::powif64 => ("__powidf2", 2, fx.tcx.types.f64), // compiler-builtins
-        sym::powf32 => ("powf", 2, fx.tcx.types.f32),
-        sym::powf64 => ("pow", 2, fx.tcx.types.f64),
-        sym::logf32 => ("logf", 1, fx.tcx.types.f32),
-        sym::logf64 => ("log", 1, fx.tcx.types.f64),
-        sym::log2f32 => ("log2f", 1, fx.tcx.types.f32),
-        sym::log2f64 => ("log2", 1, fx.tcx.types.f64),
-        sym::log10f32 => ("log10f", 1, fx.tcx.types.f32),
-        sym::log10f64 => ("log10", 1, fx.tcx.types.f64),
-        sym::fabsf32 => ("fabsf", 1, fx.tcx.types.f32),
-        sym::fabsf64 => ("fabs", 1, fx.tcx.types.f64),
-        sym::fmaf32 => ("fmaf", 3, fx.tcx.types.f32),
-        sym::fmaf64 => ("fma", 3, fx.tcx.types.f64),
-        sym::copysignf32 => ("copysignf", 2, fx.tcx.types.f32),
-        sym::copysignf64 => ("copysign", 2, fx.tcx.types.f64),
-        sym::floorf32 => ("floorf", 1, fx.tcx.types.f32),
-        sym::floorf64 => ("floor", 1, fx.tcx.types.f64),
-        sym::ceilf32 => ("ceilf", 1, fx.tcx.types.f32),
-        sym::ceilf64 => ("ceil", 1, fx.tcx.types.f64),
-        sym::truncf32 => ("truncf", 1, fx.tcx.types.f32),
-        sym::truncf64 => ("trunc", 1, fx.tcx.types.f64),
-        sym::rintf32 => ("rintf", 1, fx.tcx.types.f32),
-        sym::rintf64 => ("rint", 1, fx.tcx.types.f64),
-        sym::roundf32 => ("roundf", 1, fx.tcx.types.f32),
-        sym::roundf64 => ("round", 1, fx.tcx.types.f64),
-        sym::roundevenf32 => ("roundevenf", 1, fx.tcx.types.f32),
-        sym::roundevenf64 => ("roundeven", 1, fx.tcx.types.f64),
-        sym::sinf32 => ("sinf", 1, fx.tcx.types.f32),
-        sym::sinf64 => ("sin", 1, fx.tcx.types.f64),
-        sym::cosf32 => ("cosf", 1, fx.tcx.types.f32),
-        sym::cosf64 => ("cos", 1, fx.tcx.types.f64),
+    let (name, arg_count, ty, clif_ty) = match intrinsic {
+        sym::expf32 => ("expf", 1, fx.tcx.types.f32, types::F32),
+        sym::expf64 => ("exp", 1, fx.tcx.types.f64, types::F64),
+        sym::exp2f32 => ("exp2f", 1, fx.tcx.types.f32, types::F32),
+        sym::exp2f64 => ("exp2", 1, fx.tcx.types.f64, types::F64),
+        sym::sqrtf32 => ("sqrtf", 1, fx.tcx.types.f32, types::F32),
+        sym::sqrtf64 => ("sqrt", 1, fx.tcx.types.f64, types::F64),
+        sym::powif32 => ("__powisf2", 2, fx.tcx.types.f32, types::F32), // compiler-builtins
+        sym::powif64 => ("__powidf2", 2, fx.tcx.types.f64, types::F64), // compiler-builtins
+        sym::powf32 => ("powf", 2, fx.tcx.types.f32, types::F32),
+        sym::powf64 => ("pow", 2, fx.tcx.types.f64, types::F64),
+        sym::logf32 => ("logf", 1, fx.tcx.types.f32, types::F32),
+        sym::logf64 => ("log", 1, fx.tcx.types.f64, types::F64),
+        sym::log2f32 => ("log2f", 1, fx.tcx.types.f32, types::F32),
+        sym::log2f64 => ("log2", 1, fx.tcx.types.f64, types::F64),
+        sym::log10f32 => ("log10f", 1, fx.tcx.types.f32, types::F32),
+        sym::log10f64 => ("log10", 1, fx.tcx.types.f64, types::F64),
+        sym::fabsf32 => ("fabsf", 1, fx.tcx.types.f32, types::F32),
+        sym::fabsf64 => ("fabs", 1, fx.tcx.types.f64, types::F64),
+        sym::fmaf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32),
+        sym::fmaf64 => ("fma", 3, fx.tcx.types.f64, types::F64),
+        sym::copysignf32 => ("copysignf", 2, fx.tcx.types.f32, types::F32),
+        sym::copysignf64 => ("copysign", 2, fx.tcx.types.f64, types::F64),
+        sym::floorf32 => ("floorf", 1, fx.tcx.types.f32, types::F32),
+        sym::floorf64 => ("floor", 1, fx.tcx.types.f64, types::F64),
+        sym::ceilf32 => ("ceilf", 1, fx.tcx.types.f32, types::F32),
+        sym::ceilf64 => ("ceil", 1, fx.tcx.types.f64, types::F64),
+        sym::truncf32 => ("truncf", 1, fx.tcx.types.f32, types::F32),
+        sym::truncf64 => ("trunc", 1, fx.tcx.types.f64, types::F64),
+        sym::rintf32 => ("rintf", 1, fx.tcx.types.f32, types::F32),
+        sym::rintf64 => ("rint", 1, fx.tcx.types.f64, types::F64),
+        sym::roundf32 => ("roundf", 1, fx.tcx.types.f32, types::F32),
+        sym::roundf64 => ("round", 1, fx.tcx.types.f64, types::F64),
+        sym::roundevenf32 => ("roundevenf", 1, fx.tcx.types.f32, types::F32),
+        sym::roundevenf64 => ("roundeven", 1, fx.tcx.types.f64, types::F64),
+        sym::sinf32 => ("sinf", 1, fx.tcx.types.f32, types::F32),
+        sym::sinf64 => ("sin", 1, fx.tcx.types.f64, types::F64),
+        sym::cosf32 => ("cosf", 1, fx.tcx.types.f32, types::F32),
+        sym::cosf64 => ("cos", 1, fx.tcx.types.f64, types::F64),
         _ => return false,
     };
 
@@ -301,15 +301,19 @@ fn codegen_float_intrinsic_call<'tcx>(
     let (a, b, c);
     let args = match args {
         [x] => {
-            a = [codegen_operand(fx, x)];
+            a = [codegen_operand(fx, x).load_scalar(fx)];
             &a as &[_]
         }
         [x, y] => {
-            b = [codegen_operand(fx, x), codegen_operand(fx, y)];
+            b = [codegen_operand(fx, x).load_scalar(fx), codegen_operand(fx, y).load_scalar(fx)];
             &b
         }
         [x, y, z] => {
-            c = [codegen_operand(fx, x), codegen_operand(fx, y), codegen_operand(fx, z)];
+            c = [
+                codegen_operand(fx, x).load_scalar(fx),
+                codegen_operand(fx, y).load_scalar(fx),
+                codegen_operand(fx, z).load_scalar(fx),
+            ];
             &c
         }
         _ => unreachable!(),
@@ -318,15 +322,10 @@ fn codegen_float_intrinsic_call<'tcx>(
     let layout = fx.layout_of(ty);
     let res = match intrinsic {
         sym::fmaf32 | sym::fmaf64 => {
-            let a = args[0].load_scalar(fx);
-            let b = args[1].load_scalar(fx);
-            let c = args[2].load_scalar(fx);
-            CValue::by_val(fx.bcx.ins().fma(a, b, c), layout)
+            CValue::by_val(fx.bcx.ins().fma(args[0], args[1], args[2]), layout)
         }
         sym::copysignf32 | sym::copysignf64 => {
-            let a = args[0].load_scalar(fx);
-            let b = args[1].load_scalar(fx);
-            CValue::by_val(fx.bcx.ins().fcopysign(a, b), layout)
+            CValue::by_val(fx.bcx.ins().fcopysign(args[0], args[1]), layout)
         }
         sym::fabsf32
         | sym::fabsf64
@@ -336,21 +335,29 @@ fn codegen_float_intrinsic_call<'tcx>(
         | sym::ceilf64
         | sym::truncf32
         | sym::truncf64 => {
-            let a = args[0].load_scalar(fx);
-
             let val = match intrinsic {
-                sym::fabsf32 | sym::fabsf64 => fx.bcx.ins().fabs(a),
-                sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(a),
-                sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(a),
-                sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(a),
+                sym::fabsf32 | sym::fabsf64 => fx.bcx.ins().fabs(args[0]),
+                sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(args[0]),
+                sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(args[0]),
+                sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(args[0]),
                 _ => unreachable!(),
             };
 
             CValue::by_val(val, layout)
         }
+
         // These intrinsics aren't supported natively by Cranelift.
         // Lower them to a libcall.
-        _ => fx.easy_call(name, &args, ty),
+        sym::powif32 | sym::powif64 => {
+            let input_tys: Vec<_> = vec![AbiParam::new(clif_ty), AbiParam::new(types::I32)];
+            let ret_val = fx.lib_call(name, input_tys, vec![AbiParam::new(clif_ty)], &args)[0];
+            CValue::by_val(ret_val, fx.layout_of(ty))
+        }
+        _ => {
+            let input_tys: Vec<_> = args.iter().map(|_| AbiParam::new(clif_ty)).collect();
+            let ret_val = fx.lib_call(name, input_tys, vec![AbiParam::new(clif_ty)], &args)[0];
+            CValue::by_val(ret_val, fx.layout_of(ty))
+        }
     };
 
     ret.write_cvalue(fx, res);
@@ -385,7 +392,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
 
             fx.bcx.ins().debugtrap();
         }
-        sym::copy | sym::copy_nonoverlapping => {
+        sym::copy => {
             intrinsic_args!(fx, args => (src, dst, count); intrinsic);
             let src = src.load_scalar(fx);
             let dst = dst.load_scalar(fx);
@@ -397,13 +404,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
             let byte_amount =
                 if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
 
-            if intrinsic == sym::copy_nonoverlapping {
-                // FIXME emit_small_memcpy
-                fx.bcx.call_memcpy(fx.target_config, dst, src, byte_amount);
-            } else {
-                // FIXME emit_small_memmove
-                fx.bcx.call_memmove(fx.target_config, dst, src, byte_amount);
-            }
+            // FIXME emit_small_memmove
+            fx.bcx.call_memmove(fx.target_config, dst, src, byte_amount);
         }
         sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => {
             // NOTE: the volatile variants have src and dst swapped
@@ -643,26 +645,25 @@ fn codegen_regular_intrinsic_call<'tcx>(
 
                 if do_panic {
                     let layout = fx.layout_of(ty);
-
-                    with_no_trimmed_paths!({
-                        crate::base::codegen_panic_nounwind(
-                            fx,
-                            &if layout.abi.is_uninhabited() {
-                                format!("attempted to instantiate uninhabited type `{}`", layout.ty)
-                            } else if requirement == ValidityRequirement::Zero {
+                    let msg_str = with_no_visible_paths!({
+                        with_no_trimmed_paths!({
+                            if layout.abi.is_uninhabited() {
+                                // Use this error even for the other intrinsics as it is more precise.
+                                format!("attempted to instantiate uninhabited type `{}`", ty)
+                            } else if intrinsic == sym::assert_zero_valid {
                                 format!(
                                     "attempted to zero-initialize type `{}`, which is invalid",
-                                    layout.ty
+                                    ty
                                 )
                             } else {
                                 format!(
                                     "attempted to leave type `{}` uninitialized, which is invalid",
-                                    layout.ty
+                                    ty
                                 )
-                            },
-                            source_info,
-                        )
+                            }
+                        })
                     });
+                    crate::base::codegen_panic_nounwind(fx, &msg_str, source_info);
                     return;
                 }
             }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index a1d63acfb61..034b4e8072c 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -279,9 +279,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 fx.tcx.sess.span_warn(span, "Index argument for `simd_extract` is not a constant");
                 let trap_block = fx.bcx.create_block();
                 let true_ = fx.bcx.ins().iconst(types::I8, 1);
-                fx.bcx.ins().brnz(true_, trap_block, &[]);
                 let ret_block = fx.get_block(target);
-                fx.bcx.ins().jump(ret_block, &[]);
+                fx.bcx.ins().brif(true_, trap_block, &[], ret_block, &[]);
                 fx.bcx.switch_to_block(trap_block);
                 crate::trap::trap_unimplemented(
                     fx,
@@ -825,8 +824,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 let next = fx.bcx.create_block();
                 let res_lane = fx.bcx.append_block_param(next, lane_clif_ty);
 
-                fx.bcx.ins().brnz(mask_lane, if_enabled, &[]);
-                fx.bcx.ins().jump(if_disabled, &[]);
+                fx.bcx.ins().brif(mask_lane, if_enabled, &[], if_disabled, &[]);
                 fx.bcx.seal_block(if_enabled);
                 fx.bcx.seal_block(if_disabled);
 
@@ -864,8 +862,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 let if_enabled = fx.bcx.create_block();
                 let next = fx.bcx.create_block();
 
-                fx.bcx.ins().brnz(mask_lane, if_enabled, &[]);
-                fx.bcx.ins().jump(next, &[]);
+                fx.bcx.ins().brif(mask_lane, if_enabled, &[], next, &[]);
                 fx.bcx.seal_block(if_enabled);
 
                 fx.bcx.switch_to_block(if_enabled);
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 80ce3dc9328..bed79859f51 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -57,8 +57,6 @@ mod compiler_builtins;
 mod concurrency_limiter;
 mod config;
 mod constant;
-// FIXME revert back to the external crate with Cranelift 0.93
-mod cranelift_native;
 mod debuginfo;
 mod discriminant;
 mod driver;
@@ -251,7 +249,7 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple {
     }
 }
 
-fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::TargetIsa + 'static> {
+fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn isa::TargetIsa + 'static> {
     use target_lexicon::BinaryFormat;
 
     let target_triple = crate::target_triple(sess);
@@ -285,14 +283,17 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
         }
     }
 
-    if let target_lexicon::Architecture::Aarch64(_) | target_lexicon::Architecture::X86_64 =
-        target_triple.architecture
+    if let target_lexicon::Architecture::Aarch64(_)
+    | target_lexicon::Architecture::Riscv64(_)
+    | target_lexicon::Architecture::X86_64 = target_triple.architecture
     {
-        // Windows depends on stack probes to grow the committed part of the stack
+        // Windows depends on stack probes to grow the committed part of the stack.
+        // On other platforms it helps prevents stack smashing.
         flags_builder.enable("enable_probestack").unwrap();
         flags_builder.set("probestack_strategy", "inline").unwrap();
     } else {
-        // __cranelift_probestack is not provided and inline stack probes are only supported on AArch64 and x86_64
+        // __cranelift_probestack is not provided and inline stack probes are only supported on
+        // AArch64, Riscv64 and x86_64.
         flags_builder.set("enable_probestack", "false").unwrap();
     }
 
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index be908df83e8..205411e8c27 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -28,7 +28,7 @@ pub(crate) fn maybe_create_entry_wrapper(
 
     if main_def_id.is_local() {
         let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
-        if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() {
+        if !is_jit && module.get_name(tcx.symbol_name(instance).name).is_none() {
             return;
         }
     } else if !is_primary_cgu {
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index c058ece96d8..1357b7be1e0 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -170,14 +170,6 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
     in_lhs: CValue<'tcx>,
     in_rhs: CValue<'tcx>,
 ) -> CValue<'tcx> {
-    if bin_op != BinOp::Shl && bin_op != BinOp::Shr {
-        assert_eq!(
-            in_lhs.layout().ty,
-            in_rhs.layout().ty,
-            "checked int binop requires lhs and rhs of same type"
-        );
-    }
-
     let lhs = in_lhs.load_scalar(fx);
     let rhs = in_rhs.load_scalar(fx);
 
@@ -271,21 +263,6 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
                 _ => unreachable!("invalid non-integer type {}", ty),
             }
         }
-        BinOp::Shl => {
-            let val = fx.bcx.ins().ishl(lhs, rhs);
-            let ty = fx.bcx.func.dfg.value_type(val);
-            let max_shift = i64::from(ty.bits()) - 1;
-            let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
-            (val, has_overflow)
-        }
-        BinOp::Shr => {
-            let val =
-                if !signed { fx.bcx.ins().ushr(lhs, rhs) } else { fx.bcx.ins().sshr(lhs, rhs) };
-            let ty = fx.bcx.func.dfg.value_type(val);
-            let max_shift = i64::from(ty.bits()) - 1;
-            let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
-            (val, has_overflow)
-        }
         _ => bug!("binop {:?} on checked int/uint lhs: {:?} rhs: {:?}", bin_op, in_lhs, in_rhs),
     };
 
@@ -347,12 +324,20 @@ pub(crate) fn codegen_float_binop<'tcx>(
         BinOp::Mul => b.fmul(lhs, rhs),
         BinOp::Div => b.fdiv(lhs, rhs),
         BinOp::Rem => {
-            let name = match in_lhs.layout().ty.kind() {
-                ty::Float(FloatTy::F32) => "fmodf",
-                ty::Float(FloatTy::F64) => "fmod",
+            let (name, ty) = match in_lhs.layout().ty.kind() {
+                ty::Float(FloatTy::F32) => ("fmodf", types::F32),
+                ty::Float(FloatTy::F64) => ("fmod", types::F64),
                 _ => bug!(),
             };
-            return fx.easy_call(name, &[in_lhs, in_rhs], in_lhs.layout().ty);
+
+            let ret_val = fx.lib_call(
+                name,
+                vec![AbiParam::new(ty), AbiParam::new(ty)],
+                vec![AbiParam::new(ty)],
+                &[lhs, rhs],
+            )[0];
+
+            return CValue::by_val(ret_val, in_lhs.layout());
         }
         BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
             let fltcc = match bin_op {
diff --git a/compiler/rustc_codegen_cranelift/src/pointer.rs b/compiler/rustc_codegen_cranelift/src/pointer.rs
index 31d827f83bf..b60e56720ed 100644
--- a/compiler/rustc_codegen_cranelift/src/pointer.rs
+++ b/compiler/rustc_codegen_cranelift/src/pointer.rs
@@ -30,11 +30,6 @@ impl Pointer {
         Pointer { base: PointerBase::Stack(stack_slot), offset: Offset32::new(0) }
     }
 
-    pub(crate) fn const_addr(fx: &mut FunctionCx<'_, '_, '_>, addr: i64) -> Self {
-        let addr = fx.bcx.ins().iconst(fx.pointer_type, addr);
-        Pointer { base: PointerBase::Addr(addr), offset: Offset32::new(0) }
-    }
-
     pub(crate) fn dangling(align: Align) -> Self {
         Pointer { base: PointerBase::Dangling(align), offset: Offset32::new(0) }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index a7af162687c..e0a081c9d49 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -245,7 +245,7 @@ pub(crate) fn write_clif_file(
         for flag in isa.flags().iter() {
             writeln!(file, "set {}", flag)?;
         }
-        write!(file, "target {}", isa.triple().architecture.to_string())?;
+        write!(file, "target {}", isa.triple().architecture)?;
         for isa_flag in isa.isa_flags().iter() {
             write!(file, " {}", isa_flag)?;
         }
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index a0745582d66..ecf187a0b0f 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -28,9 +28,7 @@ pub(crate) fn unsized_info<'tcx>(
         (
             &ty::Dynamic(ref data_a, _, src_dyn_kind),
             &ty::Dynamic(ref data_b, _, target_dyn_kind),
-        ) => {
-            assert_eq!(src_dyn_kind, target_dyn_kind);
-
+        ) if src_dyn_kind == target_dyn_kind => {
             let old_info =
                 old_info.expect("unsized_info: missing old info for trait upcasting coercion");
             if data_a.principal_def_id() == data_b.principal_def_id() {
@@ -55,7 +53,7 @@ pub(crate) fn unsized_info<'tcx>(
                 old_info
             }
         }
-        (_, &ty::Dynamic(ref data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()),
+        (_, ty::Dynamic(data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()),
         _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index cc1edaa97d8..58e0a498292 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -3,6 +3,7 @@
 use crate::prelude::*;
 
 use cranelift_codegen::ir::immediates::Offset32;
+use cranelift_codegen::ir::{InstructionData, Opcode};
 
 fn codegen_field<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
@@ -457,6 +458,7 @@ impl<'tcx> CPlace<'tcx> {
         }
     }
 
+    #[track_caller]
     pub(crate) fn to_ptr(self) -> Pointer {
         match self.to_ptr_maybe_unsized() {
             (ptr, None) => ptr,
@@ -464,6 +466,7 @@ impl<'tcx> CPlace<'tcx> {
         }
     }
 
+    #[track_caller]
     pub(crate) fn to_ptr_maybe_unsized(self) -> (Pointer, Option<Value>) {
         match self.inner {
             CPlaceInner::Addr(ptr, extra) => (ptr, extra),
@@ -787,7 +790,36 @@ impl<'tcx> CPlace<'tcx> {
         index: Value,
     ) -> CPlace<'tcx> {
         let (elem_layout, ptr) = match self.layout().ty.kind() {
-            ty::Array(elem_ty, _) => (fx.layout_of(*elem_ty), self.to_ptr()),
+            ty::Array(elem_ty, _) => {
+                let elem_layout = fx.layout_of(*elem_ty);
+                match self.inner {
+                    CPlaceInner::Var(local, var) => {
+                        // This is a hack to handle `vector_val.0[1]`. It doesn't allow dynamic
+                        // indexing.
+                        let lane_idx = match fx.bcx.func.dfg.insts
+                            [fx.bcx.func.dfg.value_def(index).unwrap_inst()]
+                        {
+                            InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => imm,
+                            _ => bug!(
+                                "Dynamic indexing into a vector type is not supported: {self:?}[{index}]"
+                            ),
+                        };
+                        return CPlace {
+                            inner: CPlaceInner::VarLane(
+                                local,
+                                var,
+                                lane_idx.bits().try_into().unwrap(),
+                            ),
+                            layout: elem_layout,
+                        };
+                    }
+                    CPlaceInner::Addr(addr, None) => (elem_layout, addr),
+                    CPlaceInner::Addr(_, Some(_))
+                    | CPlaceInner::VarPair(_, _, _)
+                    | CPlaceInner::VarLane(_, _, _) => bug!("Can't index into {self:?}"),
+                }
+                // FIXME use VarLane in case of Var with simd type
+            }
             ty::Slice(elem_ty) => (fx.layout_of(*elem_ty), self.to_ptr_maybe_unsized().0),
             _ => bug!("place_index({:?})", self.layout().ty),
         };
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index f04fb82de8c..b7bfd8fd395 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -43,10 +43,29 @@ pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -
 
 pub(crate) fn get_ptr_and_method_ref<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
-    arg: CValue<'tcx>,
+    mut arg: CValue<'tcx>,
     idx: usize,
 ) -> (Pointer, Value) {
     let (ptr, vtable) = 'block: {
+        if let Abi::Scalar(_) = arg.layout().abi {
+            'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr()
+                && !arg.layout().ty.is_region_ptr()
+            {
+                for i in 0..arg.layout().fields.count() {
+                    let field = arg.value_field(fx, mir::Field::new(i));
+                    if !field.layout().is_zst() {
+                        // we found the one non-zero-sized field that is allowed
+                        // now find *its* non-zero-sized field, or stop if it's a
+                        // pointer
+                        arg = field;
+                        continue 'descend_newtypes;
+                    }
+                }
+
+                bug!("receiver has no non-zero-sized fields {:?}", arg);
+            }
+        }
+
         if let ty::Ref(_, ty, _) = arg.layout().ty.kind() {
             if ty.is_dyn_star() {
                 let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap().ty);
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 8aa744ce935..6a0d0ca55c2 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -358,9 +358,9 @@ fn link_rlib<'a>(
             let (data, _) = create_wrapper_file(sess, b".bundled_lib".to_vec(), &src);
             let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
             packed_bundled_libs.push(wrapper_file);
-        } else if let Some(name) = lib.name {
+        } else {
             let path =
-                find_native_static_library(name.as_str(), lib.verbatim, &lib_search_paths, sess);
+                find_native_static_library(lib.name.as_str(), lib.verbatim, &lib_search_paths, sess);
             ab.add_archive(&path, Box::new(|_| false)).unwrap_or_else(|error| {
                 sess.emit_fatal(errors::AddNativeLibrary { library_path: path, error })});
         }
@@ -436,7 +436,7 @@ fn collate_raw_dylibs<'a, 'b>(
     for lib in used_libraries {
         if lib.kind == NativeLibKind::RawDylib {
             let ext = if lib.verbatim { "" } else { ".dll" };
-            let name = format!("{}{}", lib.name.expect("unnamed raw-dylib library"), ext);
+            let name = format!("{}{}", lib.name, ext);
             let imports = dylib_table.entry(name.clone()).or_default();
             for import in &lib.dll_imports {
                 if let Some(old_import) = imports.insert(import.name, import) {
@@ -1199,7 +1199,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
                     .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
                     .unwrap_or(stem);
 
-                // GCC can have an optional target prefix.
+                // GCC/Clang can have an optional target prefix.
                 let flavor = if stem == "emcc" {
                     LinkerFlavor::EmCc
                 } else if stem == "gcc"
@@ -1207,7 +1207,9 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
                     || stem == "g++"
                     || stem.ends_with("-g++")
                     || stem == "clang"
+                    || stem.ends_with("-clang")
                     || stem == "clang++"
+                    || stem.ends_with("-clang++")
                 {
                     LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
                 } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
@@ -1294,7 +1296,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
         .iter()
         .filter(|l| relevant_lib(sess, l))
         .filter_map(|lib| {
-            let name = lib.name?;
+            let name = lib.name;
             match lib.kind {
                 NativeLibKind::Static { bundle: Some(false), .. }
                 | NativeLibKind::Dylib { .. }
@@ -1315,6 +1317,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
                 // These are included, no need to print them
                 NativeLibKind::Static { bundle: None | Some(true), .. }
                 | NativeLibKind::LinkArg
+                | NativeLibKind::WasmImportModule
                 | NativeLibKind::RawDylib => None,
             }
         })
@@ -2273,21 +2276,18 @@ fn add_native_libs_from_crate(
 
     let mut last = (None, NativeLibKind::Unspecified, false);
     for lib in native_libs {
-        let Some(name) = lib.name else {
-            continue;
-        };
         if !relevant_lib(sess, lib) {
             continue;
         }
 
         // Skip if this library is the same as the last.
-        last = if (lib.name, lib.kind, lib.verbatim) == last {
+        last = if (Some(lib.name), lib.kind, lib.verbatim) == last {
             continue;
         } else {
-            (lib.name, lib.kind, lib.verbatim)
+            (Some(lib.name), lib.kind, lib.verbatim)
         };
 
-        let name = name.as_str();
+        let name = lib.name.as_str();
         let verbatim = lib.verbatim;
         match lib.kind {
             NativeLibKind::Static { bundle, whole_archive } => {
@@ -2344,6 +2344,7 @@ fn add_native_libs_from_crate(
             NativeLibKind::RawDylib => {
                 // Handled separately in `linker_with_args`.
             }
+            NativeLibKind::WasmImportModule => {}
             NativeLibKind::LinkArg => {
                 if link_static {
                     cmd.arg(name);
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 7b58e55dbe8..e403a1fd8ae 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -10,6 +10,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::exported_symbols::{
     metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
 };
+use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::Instance;
@@ -41,9 +42,7 @@ pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel {
     }
 }
 
-fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<SymbolExportInfo> {
-    assert_eq!(cnum, LOCAL_CRATE);
-
+fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<SymbolExportInfo> {
     if !tcx.sess.opts.output_types.should_codegen() {
         return Default::default();
     }
@@ -154,10 +153,10 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
     reachable_non_generics
 }
 
-fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     let export_threshold = threshold(tcx);
 
-    if let Some(&info) = tcx.reachable_non_generics(def_id.krate).get(&def_id) {
+    if let Some(&info) = tcx.reachable_non_generics(LOCAL_CRATE).get(&def_id.to_def_id()) {
         info.level.is_below_threshold(export_threshold)
     } else {
         false
@@ -170,10 +169,8 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b
 
 fn exported_symbols_provider_local(
     tcx: TyCtxt<'_>,
-    cnum: CrateNum,
+    _: LocalCrate,
 ) -> &[(ExportedSymbol<'_>, SymbolExportInfo)] {
-    assert_eq!(cnum, LOCAL_CRATE);
-
     if !tcx.sess.opts.output_types.should_codegen() {
         return &[];
     }
@@ -595,7 +592,7 @@ fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, S
 
     let mut ret = FxHashMap::default();
     for (def_id, lib) in tcx.foreign_modules(cnum).iter() {
-        let module = def_id_to_native_lib.get(&def_id).and_then(|s| s.wasm_import_module);
+        let module = def_id_to_native_lib.get(&def_id).and_then(|s| s.wasm_import_module());
         let Some(module) = module else { continue };
         ret.extend(lib.foreign_items.iter().map(|id| {
             assert_eq!(id.krate, cnum);
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index f9bb8359208..037b07dec62 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -43,7 +43,7 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
     }
 }
 
-fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
+fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
     if cfg!(debug_assertions) {
         let def_kind = tcx.def_kind(did);
         assert!(
@@ -52,7 +52,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
         );
     }
 
-    let did = did.expect_local();
     let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did));
     let mut codegen_fn_attrs = CodegenFnAttrs::new();
     if tcx.should_inherit_track_caller(did) {
diff --git a/compiler/rustc_codegen_ssa/src/glue.rs b/compiler/rustc_codegen_ssa/src/glue.rs
index 0f6e6032f9b..c34f1dbf856 100644
--- a/compiler/rustc_codegen_ssa/src/glue.rs
+++ b/compiler/rustc_codegen_ssa/src/glue.rs
@@ -46,7 +46,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 // NOTE: ideally, we want the effects of both `unchecked_smul` and `unchecked_umul`
                 // (resulting in `mul nsw nuw` in LLVM IR), since we know that the multiplication
                 // cannot signed wrap, and that both operands are non-negative. But at the time of writing,
-                // `BuilderMethods` can't do this, and it doesn't seem to enable any further optimizations.
+                // the `LLVM-C` binding can't do this, and it doesn't seem to enable any further optimizations.
                 bx.unchecked_smul(info.unwrap(), bx.const_usize(unit.size.bytes())),
                 bx.const_usize(unit.align.abi.bytes()),
             )
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 8e721a84eaf..81227b04e8a 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -118,7 +118,7 @@ bitflags::bitflags! {
 #[derive(Clone, Debug, Encodable, Decodable, HashStable)]
 pub struct NativeLib {
     pub kind: NativeLibKind,
-    pub name: Option<Symbol>,
+    pub name: Symbol,
     pub filename: Option<Symbol>,
     pub cfg: Option<ast::MetaItem>,
     pub verbatim: bool,
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 71c71d59b7a..bdfc0aa1c30 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -563,15 +563,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // with #[rustc_inherit_overflow_checks] and inlined from
         // another crate (mostly core::num generic/#[inline] fns),
         // while the current crate doesn't use overflow checks.
-        if !bx.cx().check_overflow() {
-            let overflow_not_to_check = match msg {
-                AssertKind::OverflowNeg(..) => true,
-                AssertKind::Overflow(op, ..) => op.is_checkable(),
-                _ => false,
-            };
-            if overflow_not_to_check {
-                const_cond = Some(expected);
-            }
+        if !bx.cx().check_overflow() && msg.is_optional_overflow_check() {
+            const_cond = Some(expected);
         }
 
         // Don't codegen the panic block if success if known.
@@ -1482,7 +1475,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     ) -> OperandRef<'tcx, Bx::Value> {
         let tcx = bx.tcx();
 
-        let mut span_to_caller_location = |span: Span| {
+        let mut span_to_caller_location = |mut span: Span| {
+            // Remove `Inlined` marks as they pollute `expansion_cause`.
+            while span.is_inlined() {
+                span.remove_mark();
+            }
             let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
             let caller = tcx.sess.source_map().lookup_char_pos(topmost.lo());
             let const_loc = tcx.const_caller_location((
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 708f3bc0c78..6e32c28a42c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -241,12 +241,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
         let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
 
-        // FIXME(eddyb) maybe name the return place as `_0` or `return`?
-        if local == mir::RETURN_PLACE && !self.mir.local_decls[mir::RETURN_PLACE].is_user_variable()
-        {
-            return;
-        }
-
         let vars = match &self.per_local_var_debug_info {
             Some(per_local) => &per_local[local],
             None => return,
@@ -303,7 +297,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         let local_ref = &self.locals[local];
 
-        let name = if bx.sess().fewer_names() {
+        // FIXME Should the return place be named?
+        let name = if bx.sess().fewer_names() || local == mir::RETURN_PLACE {
             None
         } else {
             Some(match whole_local_var.or(fallback_var.clone()) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 3d856986fb4..13c4fa132d8 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -663,17 +663,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 };
                 bx.checked_binop(oop, input_ty, lhs, rhs)
             }
-            mir::BinOp::Shl | mir::BinOp::Shr => {
-                let lhs_llty = bx.cx().val_ty(lhs);
-                let rhs_llty = bx.cx().val_ty(rhs);
-                let invert_mask = common::shift_mask_val(bx, lhs_llty, rhs_llty, true);
-                let outer_bits = bx.and(rhs, invert_mask);
-
-                let of = bx.icmp(IntPredicate::IntNE, outer_bits, bx.cx().const_null(rhs_llty));
-                let val = self.codegen_scalar_binop(bx, op, lhs, rhs, input_ty);
-
-                (val, of)
-            }
             _ => bug!("Operator `{:?}` is not a checkable operator", op),
         };
 
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index 6dcfdc14790..088a824fd8f 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -32,8 +32,7 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
 /// it is a trait impl/function, return if it has a `const` modifier. If it is an intrinsic,
 /// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return
 /// `Constness::NotConst`.
-fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
-    let def_id = def_id.expect_local();
+fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
     let node = tcx.hir().get_by_def_id(def_id);
 
     match node {
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
index cf52299b7ba..76c8d0a975a 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
@@ -111,7 +111,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         location
     }
 
-    pub(crate) fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
+    pub(crate) fn location_triple_for_span(&self, mut span: Span) -> (Symbol, u32, u32) {
+        // Remove `Inlined` marks as they pollute `expansion_cause`.
+        while span.is_inlined() {
+            span.remove_mark();
+        }
         let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
         let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
         (
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 92fa59aec6e..c134d3a6b2f 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -155,7 +155,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
 
     /// Whether Assert(OverflowNeg) and Assert(Overflow) MIR terminators should actually
     /// check for overflow.
-    fn ignore_checkable_overflow_assertions(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+    fn ignore_optional_overflow_checks(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
     /// Entry point for obtaining the MIR of anything that should get evaluated.
     /// So not just functions and shims, but also const/static initializers, anonymous
@@ -474,7 +474,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     }
 
     #[inline(always)]
-    fn ignore_checkable_overflow_assertions(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
+    fn ignore_optional_overflow_checks(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
         false
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 685a5599cde..c2d1bc11c37 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -138,12 +138,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
 
             Assert { ref cond, expected, ref msg, target, cleanup } => {
-                let ignored = M::ignore_checkable_overflow_assertions(self)
-                    && match msg {
-                        mir::AssertKind::OverflowNeg(..) => true,
-                        mir::AssertKind::Overflow(op, ..) => op.is_checkable(),
-                        _ => false,
-                    };
+                let ignored =
+                    M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check();
                 let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?;
                 if ignored || expected == cond_val {
                     self.go_to_block(target);
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 db55dbc2bfd..0d9cd78fe12 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -246,7 +246,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
             self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
         }
 
-        if !tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) {
+        if !tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
             self.visit_body(&body);
         }
 
@@ -643,7 +643,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 if base_ty.is_unsafe_ptr() {
                     if proj_base.is_empty() {
                         let decl = &self.body.local_decls[place_local];
-                        if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
+                        if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
                             let span = decl.source_info.span;
                             self.check_static(def_id, span);
                             return;
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index e586720a0d0..c0f5b3725b3 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -704,7 +704,7 @@ pub mod ty {
 
         fn importance(&self) -> DiagnosticImportance {
             match self.0 {
-                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
+                mir::LocalKind::Temp => DiagnosticImportance::Secondary,
                 mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
                     DiagnosticImportance::Primary
                 }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
index 43806035a44..f01ab4c5d61 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
@@ -30,7 +30,7 @@ pub fn check_live_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
         return;
     }
 
-    if tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) {
+    if tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
         return;
     }
 
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 bb4b7ad50b8..6758cba2eed 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -9,7 +9,7 @@ use rustc_middle::mir;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
 use rustc_trait_selection::traits::{
-    self, ImplSource, Obligation, ObligationCause, SelectionContext,
+    self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
 };
 
 use super::ConstCx;
@@ -184,7 +184,10 @@ impl Qualif for NeedsNonConstDrop {
         }
 
         // If we had any errors, then it's bad
-        !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
+        let ocx = ObligationCtxt::new(&infcx);
+        ocx.register_obligations(impl_src.nested_obligations());
+        let errors = ocx.select_all_or_error();
+        !errors.is_empty()
     }
 
     fn in_adt_inherently<'tcx>(
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 3f3b66b0645..648a86d32fc 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -106,8 +106,9 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
         debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location);
         // We're only interested in temporaries and the return place
         match self.ccx.body.local_kind(index) {
-            LocalKind::Temp | LocalKind::ReturnPointer => {}
-            LocalKind::Arg | LocalKind::Var => return,
+            LocalKind::Arg => return,
+            LocalKind::Temp if self.ccx.body.local_decls[index].is_user_variable() => return,
+            LocalKind::ReturnPointer | LocalKind::Temp => {}
         }
 
         // Ignore drops, if the temp gets promoted,
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 49b1e6d967c..e0939d1d1ba 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -564,15 +564,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             );
                         }
                     }
-                    Shl | Shr => {
-                        for x in [a, b] {
-                            check_kinds!(
-                                x,
-                                "Cannot perform checked shift on non-integer type {:?}",
-                                ty::Uint(..) | ty::Int(..)
-                            )
-                        }
-                    }
                     _ => self.fail(location, format!("There is no checked version of {:?}", op)),
                 }
             }
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 29cb2c0a33e..24cf9812a25 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -9,7 +9,7 @@ edition = "2021"
 arrayvec = { version = "0.7", default-features = false }
 bitflags = "1.2.1"
 cfg-if = "1.0"
-ena = "0.14.1"
+ena = "0.14.2"
 indexmap = { version = "1.9.1" }
 jobserver_crate = { version = "0.1.13", package = "jobserver" }
 libc = "0.2"
@@ -36,8 +36,15 @@ elsa = "1.8"
 [dependencies.parking_lot]
 version = "0.11"
 
-[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["fileapi", "psapi", "winerror"] }
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
+features = [
+    "Win32_Foundation",
+    "Win32_Storage_FileSystem",
+    "Win32_System_IO",
+    "Win32_System_ProcessStatus",
+    "Win32_System_Threading",
+]
 
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
 memmap2 = "0.2.1"
diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs
index e395d8dbbbf..efdb44248d1 100644
--- a/compiler/rustc_data_structures/src/flock.rs
+++ b/compiler/rustc_data_structures/src/flock.rs
@@ -4,9 +4,6 @@
 //! green/native threading. This is just a bare-bones enough solution for
 //! librustdoc, it is not production quality at all.
 
-#![allow(non_camel_case_types)]
-#![allow(nonstandard_style)]
-
 cfg_if! {
     if #[cfg(target_os = "linux")] {
         mod linux;
@@ -16,7 +13,7 @@ cfg_if! {
         use unix as imp;
     } else if #[cfg(windows)] {
         mod windows;
-        use windows as imp;
+        use self::windows as imp;
     } else {
         mod unsupported;
         use unsupported as imp;
diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs
index 43e6caaa18d..da128f464a6 100644
--- a/compiler/rustc_data_structures/src/flock/windows.rs
+++ b/compiler/rustc_data_structures/src/flock/windows.rs
@@ -1,13 +1,16 @@
 use std::fs::{File, OpenOptions};
 use std::io;
-use std::mem;
 use std::os::windows::prelude::*;
 use std::path::Path;
 
-use winapi::shared::winerror::ERROR_INVALID_FUNCTION;
-use winapi::um::fileapi::LockFileEx;
-use winapi::um::minwinbase::{LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, OVERLAPPED};
-use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE};
+use windows::{
+    Win32::Foundation::{ERROR_INVALID_FUNCTION, HANDLE},
+    Win32::Storage::FileSystem::{
+        LockFileEx, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, LOCKFILE_EXCLUSIVE_LOCK,
+        LOCKFILE_FAIL_IMMEDIATELY, LOCK_FILE_FLAGS,
+    },
+    Win32::System::IO::OVERLAPPED,
+};
 
 #[derive(Debug)]
 pub struct Lock {
@@ -25,7 +28,7 @@ impl Lock {
         let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
 
         let mut open_options = OpenOptions::new();
-        open_options.read(true).share_mode(share_mode);
+        open_options.read(true).share_mode(share_mode.0);
 
         if create {
             open_options.create(true).write(true);
@@ -43,33 +46,42 @@ impl Lock {
             }
         };
 
-        let ret = unsafe {
-            let mut overlapped: OVERLAPPED = mem::zeroed();
+        let mut flags = LOCK_FILE_FLAGS::default();
+        if !wait {
+            flags |= LOCKFILE_FAIL_IMMEDIATELY;
+        }
 
-            let mut dwFlags = 0;
-            if !wait {
-                dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
-            }
+        if exclusive {
+            flags |= LOCKFILE_EXCLUSIVE_LOCK;
+        }
 
-            if exclusive {
-                dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
-            }
+        let mut overlapped = OVERLAPPED::default();
 
-            debug!("attempting to acquire lock on lock file `{}`", p.display());
-            LockFileEx(file.as_raw_handle(), dwFlags, 0, 0xFFFF_FFFF, 0xFFFF_FFFF, &mut overlapped)
-        };
-        if ret == 0 {
-            let err = io::Error::last_os_error();
-            debug!("failed acquiring file lock: {}", err);
-            Err(err)
-        } else {
-            debug!("successfully acquired lock");
-            Ok(Lock { _file: file })
+        debug!("attempting to acquire lock on lock file `{}`", p.display());
+
+        unsafe {
+            LockFileEx(
+                HANDLE(file.as_raw_handle() as isize),
+                flags,
+                0,
+                u32::MAX,
+                u32::MAX,
+                &mut overlapped,
+            )
         }
+        .ok()
+        .map_err(|e| {
+            let err = io::Error::from_raw_os_error(e.code().0);
+            debug!("failed acquiring file lock: {}", err);
+            err
+        })?;
+
+        debug!("successfully acquired lock");
+        Ok(Lock { _file: file })
     }
 
     pub fn error_unsupported(err: &io::Error) -> bool {
-        err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32)
+        err.raw_os_error() == Some(ERROR_INVALID_FUNCTION.0 as i32)
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index c595bf830a3..0339fb925d4 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -79,7 +79,6 @@ pub mod sync;
 pub mod tiny_list;
 pub mod transitive_relation;
 pub mod vec_linked_list;
-pub mod vec_map;
 pub mod work_queue;
 pub use atomic_ref::AtomicRef;
 pub mod frozen;
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 91abdaadabd..27a869eb7cd 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -97,7 +97,17 @@ pub trait ObligationProcessor {
     type Error: Debug;
     type OUT: OutcomeTrait<Obligation = Self::Obligation, Error = Error<Self::Obligation, Self::Error>>;
 
-    fn needs_process_obligation(&self, obligation: &Self::Obligation) -> bool;
+    /// Implementations can provide a fast-path to obligation-processing
+    /// by counting the prefix of the passed iterator for which
+    /// `needs_process_obligation` would return false.
+    fn skippable_obligations<'a>(
+        &'a self,
+        _it: impl Iterator<Item = &'a Self::Obligation>,
+    ) -> usize {
+        0
+    }
+
+    fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool;
 
     fn process_obligation(
         &mut self,
@@ -416,6 +426,10 @@ impl<O: ForestObligation> ObligationForest<O> {
         loop {
             let mut has_changed = false;
 
+            // This is the super fast path for cheap-to-check conditions.
+            let mut index =
+                processor.skippable_obligations(self.nodes.iter().map(|n| &n.obligation));
+
             // Note that the loop body can append new nodes, and those new nodes
             // will then be processed by subsequent iterations of the loop.
             //
@@ -424,9 +438,8 @@ impl<O: ForestObligation> ObligationForest<O> {
             // `for index in 0..self.nodes.len() { ... }` because the range would
             // be computed with the initial length, and we would miss the appended
             // nodes. Therefore we use a `while` loop.
-            let mut index = 0;
             while let Some(node) = self.nodes.get_mut(index) {
-                // This test is extremely hot.
+                // This is the moderately fast path when the prefix skipping above didn't work out.
                 if node.state.get() != NodeState::Pending
                     || !processor.needs_process_obligation(&node.obligation)
                 {
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 44331683694..3d9c7f6eae2 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -796,21 +796,26 @@ fn get_thread_id() -> u32 {
 cfg_if! {
     if #[cfg(windows)] {
         pub fn get_resident_set_size() -> Option<usize> {
-            use std::mem::{self, MaybeUninit};
-            use winapi::shared::minwindef::DWORD;
-            use winapi::um::processthreadsapi::GetCurrentProcess;
-            use winapi::um::psapi::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS};
-
-            let mut pmc = MaybeUninit::<PROCESS_MEMORY_COUNTERS>::uninit();
-            match unsafe {
-                GetProcessMemoryInfo(GetCurrentProcess(), pmc.as_mut_ptr(), mem::size_of_val(&pmc) as DWORD)
-            } {
-                0 => None,
-                _ => {
-                    let pmc = unsafe { pmc.assume_init() };
-                    Some(pmc.WorkingSetSize as usize)
-                }
+            use std::mem;
+
+            use windows::{
+                Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
+                Win32::System::Threading::GetCurrentProcess,
+            };
+
+            let mut pmc = PROCESS_MEMORY_COUNTERS::default();
+            let pmc_size = mem::size_of_val(&pmc);
+            unsafe {
+                K32GetProcessMemoryInfo(
+                    GetCurrentProcess(),
+                    &mut pmc,
+                    pmc_size as u32,
+                )
             }
+            .ok()
+            .ok()?;
+
+            Some(pmc.WorkingSetSize)
         }
     } else if #[cfg(target_os = "macos")] {
         pub fn get_resident_set_size() -> Option<usize> {
diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs
deleted file mode 100644
index d1a99bcaeb7..00000000000
--- a/compiler/rustc_data_structures/src/vec_map.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-use std::borrow::Borrow;
-use std::fmt::Debug;
-use std::slice::Iter;
-use std::vec::IntoIter;
-
-use crate::stable_hasher::{HashStable, StableHasher};
-
-/// A map type implemented as a vector of pairs `K` (key) and `V` (value).
-/// It currently provides a subset of all the map operations, the rest could be added as needed.
-#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct VecMap<K, V>(Vec<(K, V)>);
-
-impl<K, V> VecMap<K, V>
-where
-    K: Debug + PartialEq,
-    V: Debug,
-{
-    pub fn new() -> Self {
-        VecMap(Default::default())
-    }
-
-    /// Sets the value of the entry, and returns the entry's old value.
-    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
-        if let Some(elem) = self.0.iter_mut().find(|(key, _)| *key == k) {
-            Some(std::mem::replace(&mut elem.1, v))
-        } else {
-            self.0.push((k, v));
-            None
-        }
-    }
-
-    /// Removes the entry from the map and returns the removed value
-    pub fn remove(&mut self, k: &K) -> Option<V> {
-        self.0.iter().position(|(k2, _)| k2 == k).map(|pos| self.0.remove(pos).1)
-    }
-
-    /// Gets a reference to the value in the entry.
-    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
-    where
-        K: Borrow<Q>,
-        Q: Eq,
-    {
-        self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1)
-    }
-
-    /// Gets a mutable reference to the value in the entry.
-    pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
-    where
-        K: Borrow<Q>,
-        Q: Eq,
-    {
-        self.0.iter_mut().find(|(key, _)| k == key.borrow()).map(|elem| &mut elem.1)
-    }
-
-    /// Returns the any value corresponding to the supplied predicate filter.
-    ///
-    /// The supplied predicate will be applied to each (key, value) pair and it will return a
-    /// reference to the values where the predicate returns `true`.
-    pub fn any_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> {
-        self.0.iter().find(|kv| predicate(kv)).map(|elem| &elem.1)
-    }
-
-    /// Returns the value corresponding to the supplied predicate filter. It crashes if there's
-    /// more than one matching element.
-    ///
-    /// The supplied predicate will be applied to each (key, value) pair and it will return a
-    /// reference to the value where the predicate returns `true`.
-    pub fn get_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> {
-        let mut filter = self.0.iter().filter(|kv| predicate(kv));
-        let (_, value) = filter.next()?;
-        // This should return just one element, otherwise it's a bug
-        assert!(
-            filter.next().is_none(),
-            "Collection {self:#?} should have just one matching element"
-        );
-        Some(value)
-    }
-
-    /// Returns `true` if the map contains a value for the specified key.
-    ///
-    /// The key may be any borrowed form of the map's key type,
-    /// [`Eq`] on the borrowed form *must* match those for
-    /// the key type.
-    pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
-    where
-        K: Borrow<Q>,
-        Q: Eq,
-    {
-        self.get(k).is_some()
-    }
-
-    /// Returns `true` if the map contains no elements.
-    pub fn is_empty(&self) -> bool {
-        self.0.is_empty()
-    }
-
-    pub fn iter(&self) -> Iter<'_, (K, V)> {
-        self.into_iter()
-    }
-
-    pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
-        self.into_iter()
-    }
-
-    pub fn retain(&mut self, f: impl Fn(&(K, V)) -> bool) {
-        self.0.retain(f)
-    }
-}
-
-impl<K, V> Default for VecMap<K, V> {
-    #[inline]
-    fn default() -> Self {
-        Self(Default::default())
-    }
-}
-
-impl<K, V> From<Vec<(K, V)>> for VecMap<K, V> {
-    fn from(vec: Vec<(K, V)>) -> Self {
-        Self(vec)
-    }
-}
-
-impl<K, V> Into<Vec<(K, V)>> for VecMap<K, V> {
-    fn into(self) -> Vec<(K, V)> {
-        self.0
-    }
-}
-
-impl<K, V> FromIterator<(K, V)> for VecMap<K, V> {
-    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
-        Self(iter.into_iter().collect())
-    }
-}
-
-impl<'a, K, V> IntoIterator for &'a VecMap<K, V> {
-    type Item = &'a (K, V);
-    type IntoIter = Iter<'a, (K, V)>;
-
-    #[inline]
-    fn into_iter(self) -> Self::IntoIter {
-        self.0.iter()
-    }
-}
-
-impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut VecMap<K, V> {
-    type Item = (&'a K, &'a mut V);
-    type IntoIter = impl Iterator<Item = Self::Item>;
-
-    #[inline]
-    fn into_iter(self) -> Self::IntoIter {
-        self.0.iter_mut().map(|(k, v)| (&*k, v))
-    }
-}
-
-impl<K, V> IntoIterator for VecMap<K, V> {
-    type Item = (K, V);
-    type IntoIter = IntoIter<(K, V)>;
-
-    #[inline]
-    fn into_iter(self) -> Self::IntoIter {
-        self.0.into_iter()
-    }
-}
-
-impl<K: PartialEq + Debug, V: Debug> Extend<(K, V)> for VecMap<K, V> {
-    fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
-        for (k, v) in iter {
-            self.insert(k, v);
-        }
-    }
-
-    fn extend_one(&mut self, (k, v): (K, V)) {
-        self.insert(k, v);
-    }
-
-    fn extend_reserve(&mut self, additional: usize) {
-        self.0.extend_reserve(additional);
-    }
-}
-
-impl<K, V, CTX> HashStable<CTX> for VecMap<K, V>
-where
-    K: HashStable<CTX> + Eq,
-    V: HashStable<CTX>,
-{
-    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        self.0.hash_stable(hcx, hasher)
-    }
-}
-
-#[cfg(test)]
-mod tests;
diff --git a/compiler/rustc_data_structures/src/vec_map/tests.rs b/compiler/rustc_data_structures/src/vec_map/tests.rs
deleted file mode 100644
index 458b60077dc..00000000000
--- a/compiler/rustc_data_structures/src/vec_map/tests.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-use super::*;
-
-impl<K, V> VecMap<K, V> {
-    fn into_vec(self) -> Vec<(K, V)> {
-        self.0.into()
-    }
-}
-
-#[test]
-fn test_from_iterator() {
-    assert_eq!(
-        std::iter::empty().collect::<VecMap<i32, bool>>().into_vec(),
-        Vec::<(i32, bool)>::new()
-    );
-    assert_eq!(std::iter::once((42, true)).collect::<VecMap<_, _>>().into_vec(), vec![(42, true)]);
-    assert_eq!(
-        [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(),
-        vec![(1, true), (2, false)]
-    );
-}
-
-#[test]
-fn test_into_iterator_owned() {
-    assert_eq!(VecMap::new().into_iter().collect::<Vec<(i32, bool)>>(), Vec::<(i32, bool)>::new());
-    assert_eq!(VecMap::from(vec![(1, true)]).into_iter().collect::<Vec<_>>(), vec![(1, true)]);
-    assert_eq!(
-        VecMap::from(vec![(1, true), (2, false)]).into_iter().collect::<Vec<_>>(),
-        vec![(1, true), (2, false)]
-    );
-}
-
-#[test]
-fn test_insert() {
-    let mut v = VecMap::new();
-    assert_eq!(v.insert(1, true), None);
-    assert_eq!(v.insert(2, false), None);
-    assert_eq!(v.clone().into_vec(), vec![(1, true), (2, false)]);
-    assert_eq!(v.insert(1, false), Some(true));
-    assert_eq!(v.into_vec(), vec![(1, false), (2, false)]);
-}
-
-#[test]
-fn test_get() {
-    let v = [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>();
-    assert_eq!(v.get(&1), Some(&true));
-    assert_eq!(v.get(&2), Some(&false));
-    assert_eq!(v.get(&3), None);
-}
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index 7b59a52cffe..73a1f79a020 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -54,8 +54,11 @@ rustc_hir_analysis = { path = "../rustc_hir_analysis" }
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
 
-[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] }
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
+features = [
+    "Win32_System_Diagnostics_Debug",
+]
 
 [features]
 llvm = ['rustc_interface/llvm']
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 555917c8b5e..8634c644176 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -1246,11 +1246,9 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     interface::try_print_query_stack(&handler, num_frames);
 
     #[cfg(windows)]
-    unsafe {
-        if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
-            // Trigger a debugger if we crashed during bootstrap
-            winapi::um::debugapi::DebugBreak();
-        }
+    if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
+        // Trigger a debugger if we crashed during bootstrap
+        unsafe { windows::Win32::System::Diagnostics::Debug::DebugBreak() };
     }
 }
 
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index df857be85ad..d104ff0891d 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -513,6 +513,7 @@ E0790: include_str!("./error_codes/E0790.md"),
 E0791: include_str!("./error_codes/E0791.md"),
 E0792: include_str!("./error_codes/E0792.md"),
 E0793: include_str!("./error_codes/E0793.md"),
+E0794: include_str!("./error_codes/E0794.md"),
 }
 
 // Undocumented removed error codes. Note that many removed error codes are documented.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0206.md b/compiler/rustc_error_codes/src/error_codes/E0206.md
index 4405a2149ce..9e85234bdbb 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0206.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0206.md
@@ -1,5 +1,5 @@
-The `Copy` trait was implemented on a type which is neither a struct nor an
-enum.
+The `Copy` trait was implemented on a type which is neither a struct, an
+enum, nor a union.
 
 Erroneous code example:
 
@@ -10,6 +10,6 @@ struct Bar;
 impl Copy for &'static mut Bar { } // error!
 ```
 
-You can only implement `Copy` for a struct or an enum.
+You can only implement `Copy` for a struct, an enum, or a union.
 The previous example will fail because `&'static mut Bar`
-is not a struct or enum.
+is not a struct, an enum, or a union.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0416.md b/compiler/rustc_error_codes/src/error_codes/E0416.md
index 7bc316dafc5..8c0edcee521 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0416.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0416.md
@@ -23,6 +23,6 @@ Or maybe did you mean to unify? Consider using a guard:
 # let (A, B, C) = (1, 2, 3);
 match (A, B, C) {
     (x, x2, see) if x == x2 => { /* A and B are equal, do one thing */ }
-    (y, z, see) => { /* A and B unequal; do another thing */ }
+    (y, z, see) => { /* A and B not equal; do another thing */ }
 }
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0794.md b/compiler/rustc_error_codes/src/error_codes/E0794.md
new file mode 100644
index 00000000000..a33802885c0
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0794.md
@@ -0,0 +1,64 @@
+A lifetime parameter of a function definition is called *late-bound* if it both:
+
+1. appears in an argument type
+2. does not appear in a generic type constraint
+
+You cannot specify lifetime arguments for late-bound lifetime parameters.
+
+Erroneous code example:
+
+```compile_fail,E0794
+fn foo<'a>(x: &'a str) -> &'a str { x }
+let _ = foo::<'static>;
+```
+
+The type of a concrete instance of a generic function is universally quantified
+over late-bound lifetime parameters. This is because we want the function to
+work for any lifetime substituted for the late-bound lifetime parameter, no
+matter where the function is called. Consequently, it doesn't make sense to
+specify arguments for late-bound lifetime parameters, since they are not
+resolved until the function's call site(s).
+
+To fix the issue, remove the specified lifetime:
+
+```
+fn foo<'a>(x: &'a str) -> &'a str { x }
+let _ = foo;
+```
+
+### Additional information
+
+Lifetime parameters that are not late-bound are called *early-bound*.
+Confusion may arise from the fact that late-bound and early-bound
+lifetime parameters are declared the same way in function definitions.
+When referring to a function pointer type, universal quantification over
+late-bound lifetime parameters can be made explicit:
+
+```
+trait BarTrait<'a> {}
+
+struct Bar<'a> {
+    s: &'a str
+}
+
+impl<'a> BarTrait<'a> for Bar<'a> {}
+
+fn bar<'a, 'b, T>(x: &'a str, _t: T) -> &'a str
+where T: BarTrait<'b>
+{
+    x
+}
+
+let bar_fn: for<'a> fn(&'a str, Bar<'static>) -> &'a str = bar; // OK
+let bar_fn2 = bar::<'static, Bar>; // Not allowed
+let bar_fn3 = bar::<Bar>; // OK
+```
+
+In the definition of `bar`, the lifetime parameter `'a` is late-bound, while
+`'b` is early-bound. This is reflected in the type annotation for `bar_fn`,
+where `'a` is universally quantified and `'b` is substituted by a specific
+lifetime. It is not allowed to explicitly specify early-bound lifetime
+arguments when late-bound lifetime parameters are present (as for `bar_fn2`,
+see issue #42868: https://github.com/rust-lang/rust/issues/42868), although the
+types that are constrained by early-bound parameters can be specified (as for
+`bar_fn3`).
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index cadd53fbd83..e1ead08ea66 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -25,8 +25,14 @@ termize = "0.1.1"
 serde = { version = "1.0.125", features = [ "derive" ] }
 serde_json = "1.0.59"
 
-[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = [ "handleapi", "synchapi", "winbase" ] }
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
+features = [
+    "Win32_Foundation",
+    "Win32_Security",
+    "Win32_System_Threading",
+    "Win32_System_WindowsProgramming",
+]
 
 [features]
 rustc_use_parallel_compiler = ['rustc_error_messages/rustc_use_parallel_compiler']
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index bab4f31e777..9866a9bffe0 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -331,7 +331,7 @@ impl CodeSuggestion {
                     });
                     buf.push_str(&part.snippet);
                     let cur_hi = sm.lookup_char_pos(part.span.hi());
-                    if cur_hi.line == cur_lo.line {
+                    if cur_hi.line == cur_lo.line && !part.snippet.is_empty() {
                         // Account for the difference between the width of the current code and the
                         // snippet being suggested, so that the *later* suggestions are correctly
                         // aligned on the screen.
diff --git a/compiler/rustc_errors/src/lock.rs b/compiler/rustc_errors/src/lock.rs
index a73472021d4..7db262abfde 100644
--- a/compiler/rustc_errors/src/lock.rs
+++ b/compiler/rustc_errors/src/lock.rs
@@ -16,10 +16,12 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
     use std::ffi::CString;
     use std::io;
 
-    use winapi::shared::ntdef::HANDLE;
-    use winapi::um::handleapi::CloseHandle;
-    use winapi::um::synchapi::{CreateMutexA, ReleaseMutex, WaitForSingleObject};
-    use winapi::um::winbase::{INFINITE, WAIT_ABANDONED, WAIT_OBJECT_0};
+    use windows::{
+        core::PCSTR,
+        Win32::Foundation::{CloseHandle, HANDLE, WAIT_ABANDONED, WAIT_OBJECT_0},
+        Win32::System::Threading::{CreateMutexA, ReleaseMutex, WaitForSingleObject},
+        Win32::System::WindowsProgramming::INFINITE,
+    };
 
     struct Handle(HANDLE);
 
@@ -42,49 +44,38 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
     }
 
     let cname = CString::new(name).unwrap();
-    unsafe {
-        // Create a named mutex, with no security attributes and also not
-        // acquired when we create it.
-        //
-        // This will silently create one if it doesn't already exist, or it'll
-        // open up a handle to one if it already exists.
-        let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr());
-        if mutex.is_null() {
-            panic!(
-                "failed to create global mutex named `{}`: {}",
-                name,
-                io::Error::last_os_error()
-            );
-        }
-        let mutex = Handle(mutex);
+    // Create a named mutex, with no security attributes and also not
+    // acquired when we create it.
+    //
+    // This will silently create one if it doesn't already exist, or it'll
+    // open up a handle to one if it already exists.
+    let mutex = unsafe { CreateMutexA(None, false, PCSTR::from_raw(cname.as_ptr().cast())) }
+        .unwrap_or_else(|_| panic!("failed to create global mutex named `{}`", name));
+    let mutex = Handle(mutex);
 
-        // Acquire the lock through `WaitForSingleObject`.
-        //
-        // A return value of `WAIT_OBJECT_0` means we successfully acquired it.
-        //
-        // A return value of `WAIT_ABANDONED` means that the previous holder of
-        // the thread exited without calling `ReleaseMutex`. This can happen,
-        // for example, when the compiler crashes or is interrupted via ctrl-c
-        // or the like. In this case, however, we are still transferred
-        // ownership of the lock so we continue.
-        //
-        // If an error happens.. well... that's surprising!
-        match WaitForSingleObject(mutex.0, INFINITE) {
-            WAIT_OBJECT_0 | WAIT_ABANDONED => {}
-            code => {
-                panic!(
-                    "WaitForSingleObject failed on global mutex named \
-                        `{}`: {} (ret={:x})",
-                    name,
-                    io::Error::last_os_error(),
-                    code
-                );
-            }
-        }
-
-        // Return a guard which will call `ReleaseMutex` when dropped.
-        Box::new(Guard(mutex))
+    // Acquire the lock through `WaitForSingleObject`.
+    //
+    // A return value of `WAIT_OBJECT_0` means we successfully acquired it.
+    //
+    // A return value of `WAIT_ABANDONED` means that the previous holder of
+    // the thread exited without calling `ReleaseMutex`. This can happen,
+    // for example, when the compiler crashes or is interrupted via ctrl-c
+    // or the like. In this case, however, we are still transferred
+    // ownership of the lock so we continue.
+    //
+    // If an error happens.. well... that's surprising!
+    match unsafe { WaitForSingleObject(mutex.0, INFINITE) } {
+        WAIT_OBJECT_0 | WAIT_ABANDONED => (),
+        err => panic!(
+            "WaitForSingleObject failed on global mutex named `{}`: {} (ret={:x})",
+            name,
+            io::Error::last_os_error(),
+            err.0
+        ),
     }
+
+    // Return a guard which will call `ReleaseMutex` when dropped.
+    Box::new(Guard(mutex))
 }
 
 #[cfg(not(windows))]
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index b1d9cea2773..6bc393c6534 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -245,12 +245,24 @@ pub(super) fn emit_frag_parse_err(
                 e.note(
                     "the macro call doesn't expand to an expression, but it can expand to a statement",
                 );
-                e.span_suggestion_verbose(
-                    site_span.shrink_to_hi(),
-                    "add `;` to interpret the expansion as a statement",
-                    ";",
-                    Applicability::MaybeIncorrect,
-                );
+
+                if parser.token == token::Semi {
+                    if let Ok(snippet) = parser.sess.source_map().span_to_snippet(site_span) {
+                        e.span_suggestion_verbose(
+                            site_span,
+                            "surround the macro invocation with `{}` to interpret the expansion as a statement",
+                            format!("{{ {}; }}", snippet),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                } else {
+                    e.span_suggestion_verbose(
+                        site_span.shrink_to_hi(),
+                        "add `;` to interpret the expansion as a statement",
+                        ";",
+                        Applicability::MaybeIncorrect,
+                    );
+                }
             }
         },
         _ => annotate_err_with_kind(&mut e, kind, site_span),
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 47a8b4bc488..a07cb65170d 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -367,7 +367,7 @@ impl LockstepIterSize {
 ///
 /// Example: `$($($x $y)+*);+` -- we need to make sure that `x` and `y` repeat the same amount as
 /// each other at the given depth when the macro was invoked. If they don't it might mean they were
-/// declared at unequal depths or there was a compile bug. For example, if we have 3 repetitions of
+/// declared at depths which weren't equal or there was a compiler bug. For example, if we have 3 repetitions of
 /// the outer sequence and 4 repetitions of the inner sequence for `x`, we should have the same for
 /// `y`; otherwise, we can't transcribe them both at the given depth.
 fn lockstep_iter_size(
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index ac93dd555b7..3d644de1665 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -91,7 +91,7 @@ declare_features! (
     /// Allows coercing non capturing closures to function pointers.
     (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None),
     /// Allows using the CMPXCHG16B target feature.
-    (accepted, cmpxchg16b_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None),
+    (accepted, cmpxchg16b_target_feature, "1.69.0", Some(44839), None),
     /// Allows usage of the `compile_error!` macro.
     (accepted, compile_error, "1.20.0", Some(40872), None),
     /// Allows `impl Trait` in function return types.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index c893b34b4ac..e0a7c864b94 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -161,7 +161,7 @@ declare_features! (
     /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
     (active, lang_items, "1.0.0", None, None),
     /// Allows the `multiple_supertrait_upcastable` lint.
-    (active, multiple_supertrait_upcastable, "CURRENT_RUSTC_VERSION", None, None),
+    (active, multiple_supertrait_upcastable, "1.69.0", None, None),
     /// Allows using `#[omit_gdb_pretty_printer_section]`.
     (active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
     /// Allows using `#[prelude_import]` on glob `use` items.
@@ -214,7 +214,7 @@ declare_features! (
     /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed.
     (active, needs_panic_runtime, "1.10.0", Some(32837), None),
     /// Allows using `+bundled,+whole-archive` native libs.
-    (active, packed_bundled_libs, "CURRENT_RUSTC_VERSION", Some(108081), None),
+    (active, packed_bundled_libs, "1.69.0", Some(108081), None),
     /// Allows using the `#![panic_runtime]` attribute.
     (active, panic_runtime, "1.10.0", Some(32837), None),
     /// Allows using `#[rustc_allow_const_fn_unstable]`.
@@ -468,7 +468,7 @@ declare_features! (
     /// Allows using the `non_exhaustive_omitted_patterns` lint.
     (active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
     /// Allows `for<T>` binders in where-clauses
-    (incomplete, non_lifetime_binders, "CURRENT_RUSTC_VERSION", Some(108185), None),
+    (incomplete, non_lifetime_binders, "1.69.0", Some(108185), None),
     /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe.
     /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
     /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 8ceb176491b..3c4fc9cb530 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -404,8 +404,12 @@ impl DefPathData {
         match *self {
             TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
 
+            // We use this name when collecting `ModChild`s.
+            // FIXME this could probably be removed with some refactoring to the name resolver.
+            ImplTraitAssocTy => Some(kw::Empty),
+
             Impl | ForeignMod | CrateRoot | Use | GlobalAsm | ClosureExpr | Ctor | AnonConst
-            | ImplTrait | ImplTraitAssocTy => None,
+            | ImplTrait => None,
         }
     }
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index f00a5f24e45..f4b46b9a131 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1673,7 +1673,6 @@ pub struct Expr<'hir> {
 impl Expr<'_> {
     pub fn precedence(&self) -> ExprPrecedence {
         match self.kind {
-            ExprKind::Box(_) => ExprPrecedence::Box,
             ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
             ExprKind::Array(_) => ExprPrecedence::Array,
             ExprKind::Call(..) => ExprPrecedence::Call,
@@ -1763,7 +1762,6 @@ impl Expr<'_> {
             | ExprKind::Lit(_)
             | ExprKind::ConstBlock(..)
             | ExprKind::Unary(..)
-            | ExprKind::Box(..)
             | ExprKind::AddrOf(..)
             | ExprKind::Binary(..)
             | ExprKind::Yield(..)
@@ -1851,7 +1849,6 @@ impl Expr<'_> {
             | ExprKind::InlineAsm(..)
             | ExprKind::AssignOp(..)
             | ExprKind::ConstBlock(..)
-            | ExprKind::Box(..)
             | ExprKind::Binary(..)
             | ExprKind::Yield(..)
             | ExprKind::DropTemps(..)
@@ -1862,8 +1859,7 @@ impl Expr<'_> {
     /// To a first-order approximation, is this a pattern?
     pub fn is_approximately_pattern(&self) -> bool {
         match &self.kind {
-            ExprKind::Box(_)
-            | ExprKind::Array(_)
+            ExprKind::Array(_)
             | ExprKind::Call(..)
             | ExprKind::Tup(_)
             | ExprKind::Lit(_)
@@ -1910,8 +1906,6 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
 
 #[derive(Debug, HashStable_Generic)]
 pub enum ExprKind<'hir> {
-    /// A `box x` expression.
-    Box(&'hir Expr<'hir>),
     /// Allow anonymous constants from an inline `const` block
     ConstBlock(AnonConst),
     /// An array (e.g., `[a, b, c, d]`).
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index 404abe2b068..37ac3723161 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -22,6 +22,12 @@ impl From<OwnerId> for HirId {
     }
 }
 
+impl From<OwnerId> for DefId {
+    fn from(value: OwnerId) -> Self {
+        value.to_def_id()
+    }
+}
+
 impl OwnerId {
     #[inline]
     pub fn to_def_id(self) -> DefId {
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index cc0f64017e4..234256ab553 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -682,7 +682,6 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo
 pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) {
     visitor.visit_id(expression.hir_id);
     match expression.kind {
-        ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression),
         ExprKind::Array(subexpressions) => {
             walk_list!(visitor, visit_expr, subexpressions);
         }
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 60fa5a99e10..0863d65d8f9 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -296,12 +296,12 @@ language_item_table! {
     // FIXME(swatinem): the following lang items are used for async lowering and
     // should become obsolete eventually.
     ResumeTy,                sym::ResumeTy,            resume_ty,                  Target::Struct,         GenericRequirement::None;
-    IdentityFuture,          sym::identity_future,     identity_future_fn,         Target::Fn,             GenericRequirement::None;
     GetContext,              sym::get_context,         get_context_fn,             Target::Fn,             GenericRequirement::None;
 
     Context,                 sym::Context,             context,                    Target::Struct,         GenericRequirement::None;
     FuturePoll,              sym::poll,                future_poll_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
 
+    Option,                  sym::Option,              option_type,                Target::Enum,           GenericRequirement::None;
     OptionSome,              sym::Some,                option_some_variant,        Target::Variant,        GenericRequirement::None;
     OptionNone,              sym::None,                option_none_variant,        Target::Variant,        GenericRequirement::None;
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index 2f4963f6bc3..3b5c67de239 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -612,7 +612,7 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes(
         if position == GenericArgPosition::Value
             && args.num_lifetime_params() != param_counts.lifetimes
         {
-            let mut err = tcx.sess.struct_span_err(span, msg);
+            let mut err = struct_span_err!(tcx.sess, span, E0794, "{}", msg);
             err.span_note(span_late, note);
             err.emit();
         } else {
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 3cd4c4afe86..8a9aac14fb6 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -75,7 +75,7 @@ pub trait AstConv<'tcx> {
     fn get_type_parameter_bounds(
         &self,
         span: Span,
-        def_id: DefId,
+        def_id: LocalDefId,
         assoc_name: Ident,
     ) -> ty::GenericPredicates<'tcx>;
 
@@ -1440,6 +1440,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             tcx.associated_items(pred.def_id())
                                 .in_definition_order()
                                 .filter(|item| item.kind == ty::AssocKind::Type)
+                                .filter(|item| tcx.opt_rpitit_info(item.def_id).is_none())
                                 .map(|item| item.def_id),
                         );
                     }
@@ -1772,9 +1773,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             ty_param_def_id, assoc_name, span,
         );
 
-        let predicates = &self
-            .get_type_parameter_bounds(span, ty_param_def_id.to_def_id(), assoc_name)
-            .predicates;
+        let predicates =
+            &self.get_type_parameter_bounds(span, ty_param_def_id, assoc_name).predicates;
 
         debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
 
@@ -2395,13 +2395,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                     tcx,
                                     infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id),
                                 );
+                                // I guess we don't need to make a universe unless we need it,
+                                // but also we're on the error path, so it doesn't matter here.
+                                let universe = infcx.create_next_universe();
                                 infcx
                                     .can_eq(
                                         ty::ParamEnv::empty(),
                                         impl_.self_ty(),
-                                        // Must fold past escaping bound vars too,
-                                        // since we have those at this point in astconv.
-                                        tcx.fold_regions(qself_ty, |_, _| tcx.lifetimes.re_erased),
+                                        tcx.replace_escaping_bound_vars_uncached(qself_ty, ty::fold::FnMutDelegate {
+                                            regions: &mut |_| tcx.lifetimes.re_erased,
+                                            types: &mut |bv| tcx.mk_placeholder(ty::PlaceholderType {
+                                                universe,
+                                                name: bv.kind,
+                                            }),
+                                            consts: &mut |bv, ty| tcx.mk_const(ty::PlaceholderConst {
+                                                universe,
+                                                name: bv
+                                            }, ty),
+                                        })
                                     )
                             })
                             && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
@@ -3056,7 +3067,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         // generate the def_id of an associated type for the trait and return as
                         // type a projection.
                         let def_id = if in_trait && tcx.lower_impl_trait_in_trait_to_assoc_ty() {
-                            tcx.associated_item_for_impl_trait_in_trait(local_def_id).to_def_id()
+                            tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id()
                         } else {
                             local_def_id.to_def_id()
                         };
@@ -3140,8 +3151,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         debug!("impl_trait_ty_to_ty: generics={:?}", generics);
         let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
-            if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
-                // Our own parameters are the resolved lifetimes.
+            // We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count`
+            // since return-position impl trait in trait squashes all of the generics from its source fn
+            // into its own generics, so the opaque's "own" params isn't always just lifetimes.
+            if let Some(i) = (param.index as usize).checked_sub(generics.count() - lifetimes.len())
+            {
+                // Resolve our own lifetime parameters.
                 let GenericParamDefKind::Lifetime { .. } = param.kind else { bug!() };
                 let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { bug!() };
                 self.ast_region_to_region(lifetime, None).into()
@@ -3316,10 +3331,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             tcx,
             trait_ref.substs.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)),
         );
+        let fn_sig = tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), fn_sig);
 
-        let ty = if let Some(arg_idx) = arg_idx { fn_sig.input(arg_idx) } else { fn_sig.output() };
-
-        Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty))
+        Some(if let Some(arg_idx) = arg_idx {
+            *fn_sig.inputs().get(arg_idx)?
+        } else {
+            fn_sig.output()
+        })
     }
 
     #[instrument(level = "trace", skip(self, generate_err))]
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 14dc9d89180..4082759006d 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -211,7 +211,7 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
         return;
     }
 
-    let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id());
+    let substs = InternalSubsts::identity_for_item(tcx, item.owner_id);
     let span = tcx.def_span(item.owner_id.def_id);
 
     if !tcx.features().impl_trait_projections {
@@ -304,7 +304,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
         ..
     }) = item.kind
     {
-        let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+        let substs = InternalSubsts::identity_for_item(tcx, def_id);
         let opaque_identity_ty = if in_trait {
             tcx.mk_projection(def_id.to_def_id(), substs)
         } else {
@@ -535,7 +535,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
                     }
                     ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
                         let trait_substs =
-                            InternalSubsts::identity_for_item(tcx, id.owner_id.to_def_id());
+                            InternalSubsts::identity_for_item(tcx, id.owner_id);
                         let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
                             tcx,
                             assoc_item,
@@ -557,7 +557,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
             check_opaque(tcx, id);
         }
         DefKind::ImplTraitPlaceholder => {
-            let parent = tcx.impl_trait_in_trait_parent(id.owner_id.to_def_id());
+            let parent = tcx.impl_trait_in_trait_parent_fn(id.owner_id.to_def_id());
             // Only check the validity of this opaque type if the function has a default body
             if let hir::Node::TraitItem(hir::TraitItem {
                 kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
@@ -1161,7 +1161,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     def.destructor(tcx); // force the destructor to be evaluated
 
     if def.variants().is_empty() {
-        if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() {
+        if let Some(attr) = tcx.get_attrs(def_id, sym::repr).next() {
             struct_span_err!(
                 tcx.sess,
                 attr.span,
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 6e6f8c1533b..49665525967 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -583,13 +583,13 @@ fn compare_asyncness<'tcx>(
 #[instrument(skip(tcx), level = "debug", ret)]
 pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
+    impl_m_def_id: LocalDefId,
 ) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
-    let impl_m = tcx.opt_associated_item(def_id).unwrap();
+    let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap();
     let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
     let impl_trait_ref =
         tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity();
-    let param_env = tcx.param_env(def_id);
+    let param_env = tcx.param_env(impl_m_def_id);
 
     // First, check a few of the same things as `compare_impl_method`,
     // just so we don't ICE during substitution later.
@@ -599,7 +599,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
 
     let trait_to_impl_substs = impl_trait_ref.substs;
 
-    let impl_m_def_id = impl_m.def_id.expect_local();
     let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id);
     let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
     let cause = ObligationCause::new(
@@ -1205,6 +1204,17 @@ fn compare_number_of_generics<'tcx>(
         return Ok(());
     }
 
+    // We never need to emit a separate error for RPITITs, since if an RPITIT
+    // has mismatched type or const generic arguments, then the method that it's
+    // inheriting the generics from will also have mismatched arguments, and
+    // we'll report an error for that instead. Delay a bug for safety, though.
+    if tcx.opt_rpitit_info(trait_.def_id).is_some() {
+        return Err(tcx.sess.delay_span_bug(
+            rustc_span::DUMMY_SP,
+            "errors comparing numbers of generics of trait/impl functions were not emitted",
+        ));
+    }
+
     let matchings = [
         ("type", trait_own_counts.types, impl_own_counts.types),
         ("const", trait_own_counts.consts, impl_own_counts.consts),
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 20b6561f8b2..1b7475486dc 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -59,6 +59,7 @@ fn equate_intrinsic_type<'tcx>(
         require_same_types(
             tcx,
             &cause,
+            ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env?
             tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id).subst_identity()),
             fty,
         );
@@ -222,6 +223,21 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 ],
                 tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
             ),
+            sym::option_payload_ptr => {
+                let option_def_id = tcx.require_lang_item(hir::LangItem::Option, None);
+                let p0 = param(0);
+                (
+                    1,
+                    vec![tcx.mk_ptr(ty::TypeAndMut {
+                        ty: tcx.mk_adt(
+                            tcx.adt_def(option_def_id),
+                            tcx.mk_substs_from_iter([ty::GenericArg::from(p0)].into_iter()),
+                        ),
+                        mutbl: hir::Mutability::Not,
+                    })],
+                    tcx.mk_ptr(ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }),
+                )
+            }
             sym::ptr_mask => (
                 1,
                 vec![
@@ -363,6 +379,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             sym::likely => (0, vec![tcx.types.bool], tcx.types.bool),
             sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool),
 
+            sym::read_via_copy => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)),
+
             sym::discriminant_value => {
                 let assoc_items = tcx.associated_item_def_ids(
                     tcx.require_lang_item(hir::LangItem::DiscriminantKind, None),
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 9acfc1b3d29..1e2b37bd50c 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -109,8 +109,8 @@ pub fn provide(providers: &mut Providers) {
     };
 }
 
-fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
-    tcx.calculate_dtor(def_id, dropck::check_drop_impl)
+fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> {
+    tcx.calculate_dtor(def_id.to_def_id(), dropck::check_drop_impl)
 }
 
 /// Given a `DefId` for an opaque type in return position, find its parent item's return
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 71050864ce0..737532b98a4 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1,7 +1,6 @@
 use crate::autoderef::Autoderef;
 use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
 
-use hir::def::DefKind;
 use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
@@ -1548,16 +1547,27 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
     if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id())
         && assoc_item.container == ty::AssocItemContainer::TraitContainer
     {
+        // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering
+        // strategy, we can't just call `check_associated_item` on the new RPITITs,
+        // because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail.
+        // That's because we need to check that the bounds of the RPITIT hold using
+        // the special substs that we create during opaque type lowering, otherwise we're
+        // getting a bunch of early bound and free regions mixed up... Haven't looked too
+        // deep into this, though.
         for arg in fn_output.walk() {
             if let ty::GenericArgKind::Type(ty) = arg.unpack()
-                && let ty::Alias(ty::Opaque, proj) = ty.kind()
-                && tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
-                && tcx.impl_trait_in_trait_parent(proj.def_id) == fn_def_id.to_def_id()
+                // RPITITs are always eagerly normalized into opaques, so always look for an
+                // opaque here.
+                && let ty::Alias(ty::Opaque, opaque_ty) = ty.kind()
+                && let Some(opaque_def_id) = opaque_ty.def_id.as_local()
+                && let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty()
+                && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin
+                && source == fn_def_id
             {
-                let span = tcx.def_span(proj.def_id);
-                let bounds = wfcx.tcx().explicit_item_bounds(proj.def_id);
+                let span = tcx.def_span(opaque_ty.def_id);
+                let bounds = wfcx.tcx().explicit_item_bounds(opaque_ty.def_id);
                 let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
-                    let bound = ty::EarlyBinder(bound).subst(tcx, proj.substs);
+                    let bound = ty::EarlyBinder(bound).subst(tcx, opaque_ty.substs);
                     let normalized_bound = wfcx.normalize(span, None, bound);
                     traits::wf::predicate_obligations(
                         wfcx.infcx,
@@ -1784,7 +1794,7 @@ fn check_variances_for_type_defn<'tcx>(
 
     // Lazily calculated because it is only needed in case of an error.
     let explicitly_bounded_params = LazyCell::new(|| {
-        let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.to_def_id());
+        let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.def_id);
         hir_generics
             .predicates
             .iter()
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 5e8f69677cf..25d56ea45c1 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -9,15 +9,16 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::ItemKind;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::infer::{self, RegionResolutionError};
+use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
+use rustc_infer::traits::Obligation;
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
 use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::misc::{
     type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason,
 };
-use rustc_trait_selection::traits::predicate_for_trait_def;
+use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_trait_selection::traits::{self, ObligationCause};
 use std::collections::BTreeMap;
 
@@ -235,7 +236,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
     use rustc_type_ir::sty::TyKind::*;
     match (source.kind(), target.kind()) {
         (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
-            if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
+            if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok()
+                && mutbl_a == *mutbl_b => {}
         (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
         (&Adt(def_a, substs_a), &Adt(def_b, substs_b))
             if def_a.is_struct() && def_b.is_struct() =>
@@ -278,7 +280,9 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
                         }
                     }
 
-                    if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
+                    if let Ok(ok) =
+                        infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, ty_a, ty_b)
+                    {
                         if ok.obligations.is_empty() {
                             create_err(
                                 "the trait `DispatchFromDyn` may only be implemented \
@@ -331,19 +335,19 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
                     ))
                     .emit();
             } else {
-                let errors = traits::fully_solve_obligations(
-                    &infcx,
-                    coerced_fields.into_iter().map(|field| {
-                        predicate_for_trait_def(
-                            tcx,
-                            param_env,
-                            cause.clone(),
+                let ocx = ObligationCtxt::new(&infcx);
+                for field in coerced_fields {
+                    ocx.register_obligation(Obligation::new(
+                        tcx,
+                        cause.clone(),
+                        param_env,
+                        ty::Binder::dummy(tcx.mk_trait_ref(
                             dispatch_from_dyn_trait,
-                            0,
                             [field.ty(tcx, substs_a), field.ty(tcx, substs_b)],
-                        )
-                    }),
-                );
+                        )),
+                    ));
+                }
+                let errors = ocx.select_all_or_error();
                 if !errors.is_empty() {
                     infcx.err_ctxt().report_fulfillment_errors(&errors);
                 }
@@ -365,11 +369,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
     }
 }
 
-pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
+pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> CoerceUnsizedInfo {
     debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
-
-    // this provider should only get invoked for local def-ids
-    let impl_did = impl_did.expect_local();
     let span = tcx.def_span(impl_did);
 
     let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
@@ -504,7 +505,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                     // we may have to evaluate constraint
                     // expressions in the course of execution.)
                     // See e.g., #41936.
-                    if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
+                    if let Ok(ok) = infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, a, b) {
                         if ok.obligations.is_empty() {
                             return None;
                         }
@@ -580,10 +581,12 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
     };
 
     // Register an obligation for `A: Trait<B>`.
+    let ocx = ObligationCtxt::new(&infcx);
     let cause = traits::ObligationCause::misc(span, impl_did);
-    let predicate =
-        predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]);
-    let errors = traits::fully_solve_obligation(&infcx, predicate);
+    let obligation =
+        Obligation::new(tcx, cause, param_env, tcx.mk_trait_ref(trait_def_id, [source, target]));
+    ocx.register_obligation(obligation);
+    let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
         infcx.err_ctxt().report_fulfillment_errors(&errors);
     }
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 07a33bcbb50..d4dfe455b29 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -10,7 +10,7 @@
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams, TreatProjections};
 use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
 use rustc_span::symbol::sym;
@@ -24,7 +24,7 @@ pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
     collect.impls_map
 }
 
-pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, (_, simp): (CrateNum, SimplifiedType)) -> &[DefId] {
+pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
     let crate_map = tcx.crate_inherent_impls(());
     tcx.arena.alloc_from_iter(
         crate_map.incoherent_impls.get(&simp).unwrap_or(&Vec::new()).iter().map(|d| d.to_def_id()),
@@ -32,9 +32,7 @@ pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, (_, simp): (CrateNum, SimplifiedT
 }
 
 /// On-demand query: yields a vector of the inherent impls for a specific type.
-pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: DefId) -> &[DefId] {
-    let ty_def_id = ty_def_id.expect_local();
-
+pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> &[DefId] {
     let crate_map = tcx.crate_inherent_impls(());
     match crate_map.inherent_impls.get(&ty_def_id) {
         Some(v) => &v[..],
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 604d54cafb5..db58f4af8ec 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -113,7 +113,7 @@ pub fn provide(providers: &mut Providers) {
 /// the AST (`hir::Generics`), recursively.
 pub struct ItemCtxt<'tcx> {
     tcx: TyCtxt<'tcx>,
-    item_def_id: DefId,
+    item_def_id: LocalDefId,
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -347,7 +347,7 @@ fn bad_placeholder<'tcx>(
 }
 
 impl<'tcx> ItemCtxt<'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> ItemCtxt<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> {
         ItemCtxt { tcx, item_def_id }
     }
 
@@ -356,7 +356,7 @@ impl<'tcx> ItemCtxt<'tcx> {
     }
 
     pub fn hir_id(&self) -> hir::HirId {
-        self.tcx.hir().local_def_id_to_hir_id(self.item_def_id.expect_local())
+        self.tcx.hir().local_def_id_to_hir_id(self.item_def_id)
     }
 
     pub fn node(&self) -> hir::Node<'tcx> {
@@ -370,20 +370,16 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
     }
 
     fn item_def_id(&self) -> DefId {
-        self.item_def_id
+        self.item_def_id.to_def_id()
     }
 
     fn get_type_parameter_bounds(
         &self,
         span: Span,
-        def_id: DefId,
+        def_id: LocalDefId,
         assoc_name: Ident,
     ) -> ty::GenericPredicates<'tcx> {
-        self.tcx.at(span).type_param_predicates((
-            self.item_def_id,
-            def_id.expect_local(),
-            assoc_name,
-        ))
+        self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_name))
     }
 
     fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option<ty::Region<'tcx>> {
@@ -839,17 +835,15 @@ fn convert_variant(
         adt_kind,
         parent_did.to_def_id(),
         recovered,
-        adt_kind == AdtKind::Struct && tcx.has_attr(parent_did.to_def_id(), sym::non_exhaustive)
-            || variant_did.map_or(false, |variant_did| {
-                tcx.has_attr(variant_did.to_def_id(), sym::non_exhaustive)
-            }),
+        adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
+            || variant_did
+                .map_or(false, |variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
     )
 }
 
-fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> {
+fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
     use rustc_hir::*;
 
-    let def_id = def_id.expect_local();
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let Node::Item(item) = tcx.hir().get(hir_id) else {
         bug!();
@@ -908,8 +902,8 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> {
     tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr)
 }
 
-fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
-    let item = tcx.hir().expect_item(def_id.expect_local());
+fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
+    let item = tcx.hir().expect_item(def_id);
 
     let (is_auto, unsafety, items) = match item.kind {
         hir::ItemKind::Trait(is_auto, unsafety, .., items) => {
@@ -1036,7 +1030,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
         });
 
     ty::TraitDef {
-        def_id,
+        def_id: def_id.to_def_id(),
         unsafety,
         paren_sugar,
         has_auto_impl: is_auto,
@@ -1091,14 +1085,13 @@ pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir
 }
 
 #[instrument(level = "debug", skip(tcx))]
-fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> {
+fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> {
     use rustc_hir::Node::*;
     use rustc_hir::*;
 
-    let def_id = def_id.expect_local();
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
 
-    let icx = ItemCtxt::new(tcx, def_id.to_def_id());
+    let icx = ItemCtxt::new(tcx, def_id);
 
     let output = match tcx.hir().get(hir_id) {
         TraitItem(hir::TraitItem {
@@ -1139,7 +1132,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>>
 
         ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
             let abi = tcx.hir().get_foreign_abi(hir_id);
-            compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi)
+            compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
         }
 
         Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => {
@@ -1338,9 +1331,12 @@ fn suggest_impl_trait<'tcx>(
     None
 }
 
-fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> {
+fn impl_trait_ref(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> {
     let icx = ItemCtxt::new(tcx, def_id);
-    let impl_ = tcx.hir().expect_item(def_id.expect_local()).expect_impl();
+    let impl_ = tcx.hir().expect_item(def_id).expect_impl();
     impl_
         .of_trait
         .as_ref()
@@ -1380,9 +1376,9 @@ fn check_impl_constness(
     }
 }
 
-fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
+fn impl_polarity(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplPolarity {
     let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
-    let item = tcx.hir().expect_item(def_id.expect_local());
+    let item = tcx.hir().expect_item(def_id);
     match &item.kind {
         hir::ItemKind::Impl(hir::Impl {
             polarity: hir::ImplPolarity::Negative(span),
@@ -1465,16 +1461,16 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate
 
 fn compute_sig_of_foreign_fn_decl<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
+    def_id: LocalDefId,
     decl: &'tcx hir::FnDecl<'tcx>,
     abi: abi::Abi,
 ) -> ty::PolyFnSig<'tcx> {
     let unsafety = if abi == abi::Abi::RustIntrinsic {
-        intrinsic_operation_unsafety(tcx, def_id)
+        intrinsic_operation_unsafety(tcx, def_id.to_def_id())
     } else {
         hir::Unsafety::Unsafe
     };
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let fty =
         ItemCtxt::new(tcx, def_id).astconv().ty_of_fn(hir_id, unsafety, abi, decl, None, None);
 
@@ -1515,31 +1511,28 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
     fty
 }
 
-fn is_foreign_item(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    match tcx.hir().get_if_local(def_id) {
-        Some(Node::ForeignItem(..)) => true,
-        Some(_) => false,
-        _ => bug!("is_foreign_item applied to non-local def-id {:?}", def_id),
+fn is_foreign_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+    match tcx.hir().get_by_def_id(def_id) {
+        Node::ForeignItem(..) => true,
+        _ => false,
     }
 }
 
-fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind> {
-    match tcx.hir().get_if_local(def_id) {
-        Some(Node::Expr(&rustc_hir::Expr {
+fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorKind> {
+    match tcx.hir().get_by_def_id(def_id) {
+        Node::Expr(&rustc_hir::Expr {
             kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }),
             ..
-        })) => tcx.hir().body(body).generator_kind(),
-        Some(_) => None,
-        _ => bug!("generator_kind applied to non-local def-id {:?}", def_id),
+        }) => tcx.hir().body(body).generator_kind(),
+        _ => None,
     }
 }
 
-fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
-    match tcx.hir().get_if_local(def_id) {
-        Some(Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. })) => {
+fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
+    match tcx.hir().get_by_def_id(def_id) {
+        Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => {
             matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias)
         }
-        Some(_) => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
-        _ => bug!("tried getting opaque_ty_origin for non-local def-id {:?}", def_id),
+        _ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 127d4fa908b..119933697a1 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -5,16 +5,16 @@ use hir::{
 };
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
 
-pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
+pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
     use rustc_hir::*;
 
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
 
     let node = tcx.hir().get(hir_id);
     let parent_def_id = match node {
@@ -121,7 +121,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                         Some(parent_def_id.to_def_id())
                     }
                     Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
-                        Some(tcx.typeck_root_def_id(def_id))
+                        Some(tcx.typeck_root_def_id(def_id.to_def_id()))
                     }
                     // Exclude `GlobalAsm` here which cannot have generics.
                     Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
@@ -140,7 +140,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             }
         }
         Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
-            Some(tcx.typeck_root_def_id(def_id))
+            Some(tcx.typeck_root_def_id(def_id.to_def_id()))
         }
         Node::Item(item) => match item.kind {
             ItemKind::OpaqueTy(hir::OpaqueTy {
@@ -189,7 +189,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                     let opt_self = Some(ty::GenericParamDef {
                         index: 0,
                         name: kw::SelfUpper,
-                        def_id,
+                        def_id: def_id.to_def_id(),
                         pure_wrt_drop: false,
                         kind: ty::GenericParamDefKind::Type {
                             has_default: false,
@@ -326,7 +326,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
         params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
             index: next_index(),
             name: Symbol::intern(arg),
-            def_id,
+            def_id: def_id.to_def_id(),
             pure_wrt_drop: false,
             kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
         }));
@@ -339,7 +339,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             params.push(ty::GenericParamDef {
                 index: next_index(),
                 name: Symbol::intern("<const_ty>"),
-                def_id,
+                def_id: def_id.to_def_id(),
                 pure_wrt_drop: false,
                 kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
             });
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 7dce29cc0bb..aa66d7bb5ef 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -3,8 +3,8 @@ use crate::astconv::AstConv;
 use rustc_hir as hir;
 use rustc_infer::traits::util;
 use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt};
-use rustc_span::def_id::DefId;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::Span;
 
 /// For associated types we include both bounds written on the type
@@ -16,12 +16,12 @@ use rustc_span::Span;
 /// `hr-associated-type-bound-1.rs`.
 fn associated_type_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
-    assoc_item_def_id: DefId,
+    assoc_item_def_id: LocalDefId,
     ast_bounds: &'tcx [hir::GenericBound<'tcx>],
     span: Span,
 ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
     let item_ty = tcx.mk_projection(
-        assoc_item_def_id,
+        assoc_item_def_id.to_def_id(),
         InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
     );
 
@@ -30,8 +30,8 @@ fn associated_type_bounds<'tcx>(
     // Associated types are implicitly sized unless a `?Sized` bound is found
     icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
 
-    let trait_def_id = tcx.parent(assoc_item_def_id);
-    let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
+    let trait_def_id = tcx.local_parent(assoc_item_def_id);
+    let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
 
     let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
         match pred.kind().skip_binder() {
@@ -45,7 +45,11 @@ fn associated_type_bounds<'tcx>(
     });
 
     let all_bounds = tcx.arena.alloc_from_iter(bounds.predicates().chain(bounds_from_parent));
-    debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), all_bounds);
+    debug!(
+        "associated_type_bounds({}) = {:?}",
+        tcx.def_path_str(assoc_item_def_id.to_def_id()),
+        all_bounds
+    );
     all_bounds
 }
 
@@ -56,7 +60,7 @@ fn associated_type_bounds<'tcx>(
 #[instrument(level = "trace", skip(tcx), ret)]
 fn opaque_type_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
-    opaque_def_id: DefId,
+    opaque_def_id: LocalDefId,
     ast_bounds: &'tcx [hir::GenericBound<'tcx>],
     item_ty: Ty<'tcx>,
     span: Span,
@@ -74,20 +78,31 @@ fn opaque_type_bounds<'tcx>(
 
 pub(super) fn explicit_item_bounds(
     tcx: TyCtxt<'_>,
-    def_id: DefId,
+    def_id: LocalDefId,
 ) -> &'_ [(ty::Predicate<'_>, Span)] {
-    // If the def_id is about an RPITIT, delegate explicit_item_bounds to the opaque_def_id that
-    // generated the synthesized associate type.
-    let rpitit_info = if let Some(ImplTraitInTraitData::Trait { opaque_def_id, .. }) =
-        tcx.opt_rpitit_info(def_id)
-    {
-        Some(opaque_def_id)
-    } else {
-        None
-    };
+    match tcx.opt_rpitit_info(def_id.to_def_id()) {
+        // RPITIT's bounds are the same as opaque type bounds, but with
+        // a projection self type.
+        Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
+            let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item();
+            let opaque_ty = item.expect_opaque_ty();
+            return opaque_type_bounds(
+                tcx,
+                opaque_def_id.expect_local(),
+                opaque_ty.bounds,
+                tcx.mk_projection(
+                    def_id.to_def_id(),
+                    ty::InternalSubsts::identity_for_item(tcx, def_id),
+                ),
+                item.span,
+            );
+        }
+        // These should have been fed!
+        Some(ty::ImplTraitInTraitData::Impl { .. }) => unreachable!(),
+        None => {}
+    }
 
-    let bounds_def_id = rpitit_info.unwrap_or(def_id);
-    let hir_id = tcx.hir().local_def_id_to_hir_id(bounds_def_id.expect_local());
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     match tcx.hir().get(hir_id) {
         hir::Node::TraitItem(hir::TraitItem {
             kind: hir::TraitItemKind::Type(bounds, _),
@@ -100,12 +115,12 @@ pub(super) fn explicit_item_bounds(
             ..
         }) => {
             let substs = InternalSubsts::identity_for_item(tcx, def_id);
-            let item_ty = if *in_trait || rpitit_info.is_some() {
-                tcx.mk_projection(def_id, substs)
+            let item_ty = if *in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() {
+                tcx.mk_projection(def_id.to_def_id(), substs)
             } else {
-                tcx.mk_opaque(def_id, substs)
+                tcx.mk_opaque(def_id.to_def_id(), substs)
             };
-            opaque_type_bounds(tcx, bounds_def_id, bounds, item_ty, *span)
+            opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
         }
         _ => bug!("item_bounds called on {:?}", def_id),
     }
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 2badd66e346..fdab87b6ace 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -62,15 +62,16 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
 /// Returns a list of user-specified type predicates for the definition with ID `def_id`.
 /// N.B., this does not include any implied/inferred constraints.
 #[instrument(level = "trace", skip(tcx), ret)]
-fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
+fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> {
     use rustc_hir::*;
 
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let node = tcx.hir().get(hir_id);
 
     let mut is_trait = None;
     let mut is_default_impl_trait = None;
 
+    // FIXME: Should ItemCtxt take a LocalDefId?
     let icx = ItemCtxt::new(tcx, def_id);
 
     const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
@@ -99,7 +100,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
             | ItemKind::Union(_, generics) => generics,
 
             ItemKind::Trait(_, _, generics, ..) | ItemKind::TraitAlias(generics, _) => {
-                is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+                is_trait = Some(ty::TraitRef::identity(tcx, def_id.to_def_id()));
                 generics
             }
             ItemKind::OpaqueTy(OpaqueTy { generics, .. }) => generics,
@@ -253,7 +254,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
     }
 
     if tcx.features().generic_const_exprs {
-        predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
+        predicates.extend(const_evaluatable_predicates_of(tcx, def_id));
     }
 
     let mut predicates: Vec<_> = predicates.into_iter().collect();
@@ -392,18 +393,18 @@ pub(super) fn trait_explicit_predicates_and_bounds(
     def_id: LocalDefId,
 ) -> ty::GenericPredicates<'_> {
     assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
-    gather_explicit_predicates_of(tcx, def_id.to_def_id())
+    gather_explicit_predicates_of(tcx, def_id)
 }
 
 pub(super) fn explicit_predicates_of<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
+    def_id: LocalDefId,
 ) -> ty::GenericPredicates<'tcx> {
     let def_kind = tcx.def_kind(def_id);
     if let DefKind::Trait = def_kind {
         // Remove bounds on associated types from the predicates, they will be
         // returned by `explicit_item_bounds`.
-        let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
+        let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id);
         let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
 
         let is_assoc_item_ty = |ty: Ty<'tcx>| {
@@ -418,7 +419,8 @@ pub(super) fn explicit_predicates_of<'tcx>(
             //   supertrait).
             if let ty::Alias(ty::Projection, projection) = ty.kind() {
                 projection.substs == trait_identity_substs
-                    && tcx.associated_item(projection.def_id).container_id(tcx) == def_id
+                    && tcx.associated_item(projection.def_id).container_id(tcx)
+                        == def_id.to_def_id()
             } else {
                 false
             }
@@ -449,7 +451,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
         }
     } else {
         if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
-            let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+            let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
             let parent_def_id = tcx.hir().get_parent_item(hir_id);
 
             if let Some(defaulted_param_def_id) =
@@ -537,9 +539,9 @@ pub(super) fn explicit_predicates_of<'tcx>(
 /// the transitive super-predicates are converted.
 pub(super) fn super_predicates_of(
     tcx: TyCtxt<'_>,
-    trait_def_id: DefId,
+    trait_def_id: LocalDefId,
 ) -> ty::GenericPredicates<'_> {
-    tcx.super_predicates_that_define_assoc_type((trait_def_id, None))
+    tcx.super_predicates_that_define_assoc_type((trait_def_id.to_def_id(), None))
 }
 
 /// Ensures that the super-predicates of the trait with a `DefId`
@@ -549,72 +551,70 @@ pub(super) fn super_predicates_that_define_assoc_type(
     tcx: TyCtxt<'_>,
     (trait_def_id, assoc_name): (DefId, Option<Ident>),
 ) -> ty::GenericPredicates<'_> {
-    if trait_def_id.is_local() {
-        debug!("local trait");
-        let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
+    let Some(trait_def_id) = trait_def_id.as_local() else {
+        // if `assoc_name` is None, then the query should've been redirected to an
+        // external provider
+        assert!(assoc_name.is_some());
+        return tcx.super_predicates_of(trait_def_id);
+    };
 
-        let Node::Item(item) = tcx.hir().get(trait_hir_id) else {
-            bug!("trait_node_id {} is not an item", trait_hir_id);
-        };
+    debug!("local trait");
+    let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id);
 
-        let (generics, bounds) = match item.kind {
-            hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits),
-            hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits),
-            _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
-        };
+    let Node::Item(item) = tcx.hir().get(trait_hir_id) else {
+        bug!("trait_node_id {} is not an item", trait_hir_id);
+    };
 
-        let icx = ItemCtxt::new(tcx, trait_def_id);
+    let (generics, bounds) = match item.kind {
+        hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits),
+        hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits),
+        _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
+    };
 
-        // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
-        let self_param_ty = tcx.types.self_param;
-        let superbounds1 = if let Some(assoc_name) = assoc_name {
-            icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name)
-        } else {
-            icx.astconv().compute_bounds(self_param_ty, bounds)
-        };
+    let icx = ItemCtxt::new(tcx, trait_def_id);
 
-        let superbounds1 = superbounds1.predicates();
-
-        // Convert any explicit superbounds in the where-clause,
-        // e.g., `trait Foo where Self: Bar`.
-        // In the case of trait aliases, however, we include all bounds in the where-clause,
-        // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
-        // as one of its "superpredicates".
-        let is_trait_alias = tcx.is_trait_alias(trait_def_id);
-        let superbounds2 = icx.type_parameter_bounds_in_generics(
-            generics,
-            item.owner_id.def_id,
-            self_param_ty,
-            OnlySelfBounds(!is_trait_alias),
-            assoc_name,
-        );
+    // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
+    let self_param_ty = tcx.types.self_param;
+    let superbounds1 = if let Some(assoc_name) = assoc_name {
+        icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name)
+    } else {
+        icx.astconv().compute_bounds(self_param_ty, bounds)
+    };
 
-        // Combine the two lists to form the complete set of superbounds:
-        let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
-        debug!(?superbounds);
+    let superbounds1 = superbounds1.predicates();
+
+    // Convert any explicit superbounds in the where-clause,
+    // e.g., `trait Foo where Self: Bar`.
+    // In the case of trait aliases, however, we include all bounds in the where-clause,
+    // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
+    // as one of its "superpredicates".
+    let is_trait_alias = tcx.is_trait_alias(trait_def_id.to_def_id());
+    let superbounds2 = icx.type_parameter_bounds_in_generics(
+        generics,
+        item.owner_id.def_id,
+        self_param_ty,
+        OnlySelfBounds(!is_trait_alias),
+        assoc_name,
+    );
+
+    // Combine the two lists to form the complete set of superbounds:
+    let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
+    debug!(?superbounds);
 
+    // Now require that immediate supertraits are converted,
+    // which will, in turn, reach indirect supertraits.
+    if assoc_name.is_none() {
         // Now require that immediate supertraits are converted,
         // which will, in turn, reach indirect supertraits.
-        if assoc_name.is_none() {
-            // Now require that immediate supertraits are converted,
-            // which will, in turn, reach indirect supertraits.
-            for &(pred, span) in superbounds {
-                debug!("superbound: {:?}", pred);
-                if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) =
-                    pred.kind().skip_binder()
-                {
-                    tcx.at(span).super_predicates_of(bound.def_id());
-                }
+        for &(pred, span) in superbounds {
+            debug!("superbound: {:?}", pred);
+            if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() {
+                tcx.at(span).super_predicates_of(bound.def_id());
             }
         }
-
-        ty::GenericPredicates { parent: None, predicates: superbounds }
-    } else {
-        // if `assoc_name` is None, then the query should've been redirected to an
-        // external provider
-        assert!(assoc_name.is_some());
-        tcx.super_predicates_of(trait_def_id)
     }
+
+    ty::GenericPredicates { parent: None, predicates: superbounds }
 }
 
 /// Returns the predicates defined on `item_def_id` of the form
@@ -622,7 +622,7 @@ pub(super) fn super_predicates_that_define_assoc_type(
 #[instrument(level = "trace", skip(tcx))]
 pub(super) fn type_param_predicates(
     tcx: TyCtxt<'_>,
-    (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
+    (item_def_id, def_id, assoc_name): (LocalDefId, LocalDefId, Ident),
 ) -> ty::GenericPredicates<'_> {
     use rustc_hir::*;
 
@@ -637,21 +637,21 @@ pub(super) fn type_param_predicates(
     let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id));
 
     // Don't look for bounds where the type parameter isn't in scope.
-    let parent = if item_def_id == param_owner.to_def_id() {
+    let parent = if item_def_id == param_owner {
         None
     } else {
-        tcx.generics_of(item_def_id).parent
+        tcx.generics_of(item_def_id).parent.map(|def_id| def_id.expect_local())
     };
 
     let mut result = parent
         .map(|parent| {
             let icx = ItemCtxt::new(tcx, parent);
-            icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name)
+            icx.get_type_parameter_bounds(DUMMY_SP, def_id, assoc_name)
         })
         .unwrap_or_default();
     let mut extend = None;
 
-    let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
+    let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id);
     let ast_generics = match tcx.hir().get(item_hir_id) {
         Node::TraitItem(item) => &item.generics,
 
@@ -673,7 +673,8 @@ pub(super) fn type_param_predicates(
                 ItemKind::Trait(_, _, generics, ..) => {
                     // Implied `Self: Trait` and supertrait bounds.
                     if param_id == item_hir_id {
-                        let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
+                        let identity_trait_ref =
+                            ty::TraitRef::identity(tcx, item_def_id.to_def_id());
                         extend =
                             Some((identity_trait_ref.without_const().to_predicate(tcx), item.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 e9963e67741..f1769415797 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -1051,9 +1051,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
     }
 }
 
-fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifetimeDefault {
+fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault {
     debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam);
-    let param_def_id = param_def_id.expect_local();
     let hir::Node::GenericParam(param) = tcx.hir().get_by_def_id(param_def_id) else {
         bug!("expected GenericParam for object_lifetime_default");
     };
@@ -1427,25 +1426,25 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
             if let ResolvedArg::LateBound(..) = def && crossed_anon_const {
                 let use_span = self.tcx.hir().span(hir_id);
                 let def_span = self.tcx.def_span(param_def_id);
-                match self.tcx.def_kind(param_def_id) {
+                let guar = match self.tcx.def_kind(param_def_id) {
                     DefKind::ConstParam => {
                         self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Const {
                             use_span,
                             def_span,
-                        });
+                        })
                     }
                     DefKind::TyParam => {
                         self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Type {
                             use_span,
                             def_span,
-                        });
+                        })
                     }
                     _ => unreachable!(),
-                }
-                return;
+                };
+                self.map.defs.insert(hir_id, ResolvedArg::Error(guar));
+            } else {
+                self.map.defs.insert(hir_id, def);
             }
-
-            self.map.defs.insert(hir_id, def);
             return;
         }
 
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index fe44fabf57d..225b1550580 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -63,7 +63,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
                 .find(|(_, node)| matches!(node, OwnerNode::Item(_)))
                 .unwrap()
                 .0
-                .to_def_id();
+                .def_id;
             let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>;
             let ty = item_ctxt.ast_ty_to_ty(hir_ty);
 
@@ -244,11 +244,13 @@ fn get_path_containing_arg_in_pat<'hir>(
     arg_path
 }
 
-pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> {
+pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty<'_>> {
     // If we are computing `type_of` the synthesized associated type for an RPITIT in the impl
     // side, use `collect_return_position_impl_trait_in_trait_tys` to infer the value of the
     // associated type in the impl.
-    if let Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) {
+    if let Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) =
+        tcx.opt_rpitit_info(def_id.to_def_id())
+    {
         match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) {
             Ok(map) => {
                 let assoc_item = tcx.associated_item(def_id);
@@ -263,23 +265,25 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
         }
     }
 
-    let def_id = def_id.expect_local();
     use rustc_hir::*;
 
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
 
-    let icx = ItemCtxt::new(tcx, def_id.to_def_id());
+    let icx = ItemCtxt::new(tcx, def_id);
 
     let output = match tcx.hir().get(hir_id) {
         Node::TraitItem(item) => match item.kind {
             TraitItemKind::Fn(..) => {
-                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                let substs = InternalSubsts::identity_for_item(tcx, def_id);
                 tcx.mk_fn_def(def_id.to_def_id(), substs)
             }
             TraitItemKind::Const(ty, body_id) => body_id
                 .and_then(|body_id| {
-                    is_suggestable_infer_ty(ty)
-                        .then(|| infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant",))
+                    is_suggestable_infer_ty(ty).then(|| {
+                        infer_placeholder_type(
+                            tcx, def_id, body_id, ty.span, item.ident, "constant",
+                        )
+                    })
                 })
                 .unwrap_or_else(|| icx.to_ty(ty)),
             TraitItemKind::Type(_, Some(ty)) => icx.to_ty(ty),
@@ -290,7 +294,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
 
         Node::ImplItem(item) => match item.kind {
             ImplItemKind::Fn(..) => {
-                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                let substs = InternalSubsts::identity_for_item(tcx, def_id);
                 tcx.mk_fn_def(def_id.to_def_id(), substs)
             }
             ImplItemKind::Const(ty, body_id) => {
@@ -335,22 +339,23 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
                     }
                 }
                 ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
-                ItemKind::Impl(hir::Impl { self_ty, .. }) => {
-                    match self_ty.find_self_aliases() {
-                        spans if spans.len() > 0 => {
-                            let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
-                            tcx.ty_error(guar)
-                        },
-                        _ => icx.to_ty(*self_ty),
+                ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
+                    spans if spans.len() > 0 => {
+                        let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf {
+                            span: spans.into(),
+                            note: (),
+                        });
+                        tcx.ty_error(guar)
                     }
+                    _ => icx.to_ty(*self_ty),
                 },
                 ItemKind::Fn(..) => {
-                    let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                    let substs = InternalSubsts::identity_for_item(tcx, def_id);
                     tcx.mk_fn_def(def_id.to_def_id(), substs)
                 }
                 ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
                     let def = tcx.adt_def(def_id);
-                    let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                    let substs = InternalSubsts::identity_for_item(tcx, def_id);
                     tcx.mk_adt(def, substs)
                 }
                 ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
@@ -364,7 +369,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
                     ..
                 }) => {
                     if in_trait && !tcx.impl_defaultness(owner).has_value() {
-                        span_bug!(tcx.def_span(def_id), "tried to get type of this RPITIT with no definition");
+                        span_bug!(
+                            tcx.def_span(def_id),
+                            "tried to get type of this RPITIT with no definition"
+                        );
                     }
                     find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
                 }
@@ -387,7 +395,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
 
         Node::ForeignItem(foreign_item) => match foreign_item.kind {
             ForeignItemKind::Fn(..) => {
-                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                let substs = InternalSubsts::identity_for_item(tcx, def_id);
                 tcx.mk_fn_def(def_id.to_def_id(), substs)
             }
             ForeignItemKind::Static(t, _) => icx.to_ty(t),
@@ -399,7 +407,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
                 tcx.type_of(tcx.hir().get_parent_item(hir_id)).subst_identity()
             }
             VariantData::Tuple(..) => {
-                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                let substs = InternalSubsts::identity_for_item(tcx, def_id);
                 tcx.mk_fn_def(def_id.to_def_id(), substs)
             }
         },
@@ -432,7 +440,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
                 Node::Expr(Expr { kind: ExprKind::ConstBlock(anon_const), .. })
                     if anon_const.hir_id == hir_id =>
                 {
-                    let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                    let substs = InternalSubsts::identity_for_item(tcx, def_id);
                     substs.as_inline_const().ty()
                 }
 
@@ -453,15 +461,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
                     tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
                 }
 
-                Node::TypeBinding(
-                    TypeBinding {
-                        hir_id: binding_id,
-                        kind: TypeBindingKind::Equality { term: Term::Const(e) },
-                        ident,
-                        ..
-                    },
-                ) if let Node::TraitRef(trait_ref) =
-                    tcx.hir().get_parent(*binding_id)
+                Node::TypeBinding(TypeBinding {
+                    hir_id: binding_id,
+                    kind: TypeBindingKind::Equality { term: Term::Const(e) },
+                    ident,
+                    ..
+                }) if let Node::TraitRef(trait_ref) = tcx.hir().get_parent(*binding_id)
                     && e.hir_id == hir_id =>
                 {
                     let Some(trait_def_id) = trait_ref.trait_def_id() else {
@@ -475,7 +480,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
                         def_id.to_def_id(),
                     );
                     if let Some(assoc_item) = assoc_item {
-                        tcx.type_of(assoc_item.def_id).subst_identity()
+                        tcx.type_of(assoc_item.def_id)
+                            .no_bound_vars()
+                            .expect("const parameter types cannot be generic")
                     } else {
                         // FIXME(associated_const_equality): add a useful error message here.
                         tcx.ty_error_with_message(
@@ -485,10 +492,13 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
                     }
                 }
 
-                Node::TypeBinding(
-                    TypeBinding { hir_id: binding_id, gen_args, kind, ident, .. },
-                ) if let Node::TraitRef(trait_ref) =
-                    tcx.hir().get_parent(*binding_id)
+                Node::TypeBinding(TypeBinding {
+                    hir_id: binding_id,
+                    gen_args,
+                    kind,
+                    ident,
+                    ..
+                }) if let Node::TraitRef(trait_ref) = tcx.hir().get_parent(*binding_id)
                     && let Some((idx, _)) =
                         gen_args.args.iter().enumerate().find(|(_, arg)| {
                             if let GenericArg::Const(ct) = arg {
@@ -517,15 +527,18 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
                         },
                         def_id.to_def_id(),
                     );
-                    if let Some(param)
-                        = assoc_item.map(|item| &tcx.generics_of(item.def_id).params[idx]).filter(|param| param.kind.is_ty_or_const())
+                    if let Some(assoc_item) = assoc_item
+                        && let param = &tcx.generics_of(assoc_item.def_id).params[idx]
+                        && matches!(param.kind, ty::GenericParamDefKind::Const { .. })
                     {
-                        tcx.type_of(param.def_id).subst_identity()
+                        tcx.type_of(param.def_id)
+                            .no_bound_vars()
+                            .expect("const parameter types cannot be generic")
                     } else {
                         // FIXME(associated_const_equality): add a useful error message here.
                         tcx.ty_error_with_message(
                             DUMMY_SP,
-                            "Could not find associated const on trait",
+                            "Could not find const param on associated item",
                         )
                     }
                 }
@@ -593,7 +606,7 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
         found: Option<ty::OpaqueHiddenType<'tcx>>,
 
         /// In the presence of dead code, typeck may figure out a hidden type
-        /// while borrowck will now. We collect these cases here and check at
+        /// while borrowck will not. We collect these cases here and check at
         /// the end that we actually found a type that matches (modulo regions).
         typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>,
     }
@@ -765,7 +778,7 @@ fn find_opaque_ty_constraints_for_rpit(
             // Use borrowck to get the type with unerased regions.
             let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
             debug!(?concrete_opaque_types);
-            for &(def_id, concrete_type) in concrete_opaque_types {
+            for (&def_id, &concrete_type) in concrete_opaque_types {
                 if def_id != self.def_id {
                     // Ignore constraints for other opaque types.
                     continue;
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index e330fcc7857..8269a6ddea5 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -7,7 +7,7 @@ use rustc_infer::traits::{ObligationCause, WellFormedLoc};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder};
 use rustc_span::def_id::LocalDefId;
-use rustc_trait_selection::traits;
+use rustc_trait_selection::traits::{self, ObligationCtxt};
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers { diagnostic_hir_wf_check, ..*providers };
@@ -31,7 +31,7 @@ fn diagnostic_hir_wf_check<'tcx>(
     tcx.sess
         .delay_span_bug(tcx.def_span(def_id), "Performed HIR wfcheck without an existing error!");
 
-    let icx = ItemCtxt::new(tcx, def_id.to_def_id());
+    let icx = ItemCtxt::new(tcx, def_id);
 
     // To perform HIR-based WF checking, we iterate over all HIR types
     // that occur 'inside' the item we're checking. For example,
@@ -66,35 +66,35 @@ fn diagnostic_hir_wf_check<'tcx>(
     impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
         fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
             let infcx = self.tcx.infer_ctxt().build();
+            let ocx = ObligationCtxt::new(&infcx);
+
             let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
             let cause = traits::ObligationCause::new(
                 ty.span,
                 self.def_id,
                 traits::ObligationCauseCode::WellFormed(None),
             );
-            let errors = traits::fully_solve_obligation(
-                &infcx,
-                traits::Obligation::new(
-                    self.tcx,
-                    cause,
-                    self.param_env,
-                    ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into())),
-                ),
-            );
-            if !errors.is_empty() {
-                debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
-                for error in errors {
-                    if error.obligation.predicate == self.predicate {
-                        // Save the cause from the greatest depth - this corresponds
-                        // to picking more-specific types (e.g. `MyStruct<u8>`)
-                        // over less-specific types (e.g. `Option<MyStruct<u8>>`)
-                        if self.depth >= self.cause_depth {
-                            self.cause = Some(error.obligation.cause);
-                            self.cause_depth = self.depth
-                        }
+
+            ocx.register_obligation(traits::Obligation::new(
+                self.tcx,
+                cause,
+                self.param_env,
+                ty::PredicateKind::WellFormed(tcx_ty.into()),
+            ));
+
+            for error in ocx.select_all_or_error() {
+                debug!("Wf-check got error for {:?}: {:?}", ty, error);
+                if error.obligation.predicate == self.predicate {
+                    // Save the cause from the greatest depth - this corresponds
+                    // to picking more-specific types (e.g. `MyStruct<u8>`)
+                    // over less-specific types (e.g. `Option<MyStruct<u8>>`)
+                    if self.depth >= self.cause_depth {
+                        self.cause = Some(error.obligation.cause);
+                        self.cause_depth = self.depth
                     }
                 }
             }
+
             self.depth += 1;
             intravisit::walk_ty(self, ty);
             self.depth -= 1;
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 58dd03811f7..91c64eeec1e 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -168,7 +168,7 @@ fn get_impl_substs(
     let assumed_wf_types =
         ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
 
-    let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id());
+    let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id);
     let impl2_substs =
         translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
 
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 62abcbbdc9f..d43230cb563 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -102,7 +102,7 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir as hir;
 use rustc_hir::Node;
-use rustc_infer::infer::{InferOk, TyCtxtInferExt};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_macros::fluent_messages;
 use rustc_middle::middle;
 use rustc_middle::ty::query::Providers;
@@ -113,7 +113,7 @@ use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 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, ObligationCauseCode};
+use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, ObligationCtxt};
 
 use std::ops::Not;
 
@@ -160,24 +160,21 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi
 fn require_same_types<'tcx>(
     tcx: TyCtxt<'tcx>,
     cause: &ObligationCause<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     expected: Ty<'tcx>,
     actual: Ty<'tcx>,
-) -> bool {
+) {
     let infcx = &tcx.infer_ctxt().build();
-    let param_env = ty::ParamEnv::empty();
-    let errors = match infcx.at(cause, param_env).eq(expected, actual) {
-        Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
+    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();
-            return false;
-        }
-    };
-
-    match &errors[..] {
-        [] => true,
-        errors => {
-            infcx.err_ctxt().report_fulfillment_errors(errors);
-            false
         }
     }
 }
@@ -296,6 +293,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         return;
     }
 
+    // Main should have no WC, so empty param env is OK here.
+    let param_env = ty::ParamEnv::empty();
     let expected_return_type;
     if let Some(term_did) = tcx.lang_items().termination() {
         let return_ty = main_fnsig.output();
@@ -306,8 +305,6 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         }
         let return_ty = return_ty.skip_binder();
         let infcx = tcx.infer_ctxt().build();
-        // Main should have no WC, so empty param env is OK here.
-        let param_env = ty::ParamEnv::empty();
         let cause = traits::ObligationCause::new(
             return_ty_span,
             main_diagnostics_def_id,
@@ -343,6 +340,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
             main_diagnostics_def_id,
             ObligationCauseCode::MainFunctionType,
         ),
+        param_env,
         se_ty,
         tcx.mk_fn_ptr(main_fnsig),
     );
@@ -417,6 +415,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                     start_def_id,
                     ObligationCauseCode::StartFunctionType,
                 ),
+                ty::ParamEnv::empty(), // start should not have any where bounds.
                 se_ty,
                 tcx.mk_fn_ptr(tcx.fn_sig(start_def_id).subst_identity()),
             );
@@ -513,7 +512,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
     // def-ID that will be used to determine the traits/predicates in
     // scope. This is derived from the enclosing item-like thing.
     let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
-    let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
+    let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.def_id);
     item_cx.astconv().ast_ty_to_ty(hir_ty)
 }
 
@@ -526,7 +525,7 @@ pub fn hir_trait_to_predicates<'tcx>(
     // def-ID that will be used to determine the traits/predicates in
     // scope. This is derived from the enclosing item-like thing.
     let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
-    let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
+    let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.def_id);
     let mut bounds = Bounds::default();
     let _ = &item_cx.astconv().instantiate_poly_trait_ref(
         hir_trait,
diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index 81fe32000d3..da72d2584e3 100644
--- a/compiler/rustc_hir_analysis/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
@@ -1,6 +1,6 @@
 use hir::Node;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt};
@@ -17,8 +17,8 @@ pub fn provide(providers: &mut Providers) {
     *providers = Providers { inferred_outlives_of, inferred_outlives_crate, ..*providers };
 }
 
-fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Clause<'_>, Span)] {
-    let id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
+fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] {
+    let id = tcx.hir().local_def_id_to_hir_id(item_def_id);
 
     if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization()
     {
@@ -45,7 +45,8 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Clause<'_
             hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => {
                 let crate_map = tcx.inferred_outlives_crate(());
 
-                let predicates = crate_map.predicates.get(&item_def_id).copied().unwrap_or(&[]);
+                let predicates =
+                    crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
 
                 if tcx.has_attr(item_def_id, sym::rustc_outlives) {
                     let mut pred: Vec<String> = predicates
diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs
index fa2ac56593b..60f8e246ad6 100644
--- a/compiler/rustc_hir_analysis/src/outlives/test.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/test.rs
@@ -6,7 +6,7 @@ pub fn test_inferred_outlives(tcx: TyCtxt<'_>) {
     for id in tcx.hir().items() {
         // For unit testing: check for a special "rustc_outlives"
         // attribute and report an error with various results if found.
-        if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_outlives) {
+        if tcx.has_attr(id.owner_id, sym::rustc_outlives) {
             let inferred_outlives_of = tcx.inferred_outlives_of(id.owner_id);
             struct_span_err!(
                 tcx.sess,
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index a8b7699b667..0a45119ff05 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -38,7 +38,7 @@ fn crate_variances(tcx: TyCtxt<'_>, (): ()) -> CrateVariancesMap<'_> {
     solve::solve_constraints(constraints_cx)
 }
 
-fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] {
+fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
     // Skip items with no generics - there's nothing to infer in them.
     if tcx.generics_of(item_def_id).count() == 0 {
         return &[];
@@ -53,7 +53,7 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] {
         | DefKind::Variant
         | DefKind::Ctor(..) => {}
         DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => {
-            return variance_of_opaque(tcx, item_def_id.expect_local());
+            return variance_of_opaque(tcx, item_def_id);
         }
         _ => {
             // Variance not relevant.
@@ -64,7 +64,7 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] {
     // Everything else must be inferred.
 
     let crate_map = tcx.crate_variances(());
-    crate_map.variances.get(&item_def_id).copied().unwrap_or(&[])
+    crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[])
 }
 
 #[instrument(level = "trace", skip(tcx), ret)]
@@ -112,10 +112,14 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             match t.kind() {
                 ty::Alias(_, ty::AliasTy { def_id, substs, .. })
-                    if matches!(
-                        self.tcx.def_kind(*def_id),
-                        DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
-                    ) =>
+                    if matches!(self.tcx.def_kind(*def_id), DefKind::OpaqueTy) =>
+                {
+                    self.visit_opaque(*def_id, substs)
+                }
+                // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) check whether this is necessary
+                // at all for RPITITs.
+                ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+                    if self.tcx.is_impl_trait_in_trait(*def_id) =>
                 {
                     self.visit_opaque(*def_id, substs)
                 }
@@ -148,7 +152,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
 
     let mut collector =
         OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances };
-    let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id());
+    let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id);
     for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() {
         let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
         debug!(?pred);
diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs
index 64614831f56..d57d05d7605 100644
--- a/compiler/rustc_hir_analysis/src/variance/test.rs
+++ b/compiler/rustc_hir_analysis/src/variance/test.rs
@@ -7,7 +7,7 @@ pub fn test_variance(tcx: TyCtxt<'_>) {
     // For unit testing: check for a special "rustc_variance"
     // attribute and report an error with various results if found.
     for id in tcx.hir().items() {
-        if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) {
+        if tcx.has_attr(id.owner_id, sym::rustc_variance) {
             let variances_of = tcx.variances_of(id.owner_id);
 
             tcx.sess.emit_err(errors::VariancesOf {
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index d715b03e40e..63ea6c90477 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1366,10 +1366,6 @@ impl<'a> State<'a> {
         self.ibox(INDENT_UNIT);
         self.ann.pre(self, AnnNode::Expr(expr));
         match expr.kind {
-            hir::ExprKind::Box(expr) => {
-                self.word_space("Box::new");
-                self.print_call_post(std::slice::from_ref(expr));
-            }
             hir::ExprKind::Array(exprs) => {
                 self.print_expr_vec(exprs);
             }
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index e19ef2ff3bf..035ccf30b24 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -299,7 +299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             {
                 // check that the `if` expr without `else` is the fn body's expr
                 if expr.span == sp {
-                    return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| {
+                    return self.get_fn_decl(hir_id).and_then(|(_, fn_decl, _)| {
                         let span = fn_decl.output.span();
                         let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?;
                         Some((span, format!("expected `{snippet}` because of this return type")))
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 6a0d5c01109..5235710a266 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -311,9 +311,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let fn_decl_span = if hir.body(body).generator_kind
                 == Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure))
             {
-                // Actually need to unwrap a few more layers of HIR to get to
+                // Actually need to unwrap one more layer of HIR to get to
                 // the _real_ closure...
-                let async_closure = hir.parent_id(hir.parent_id(parent_hir_id));
+                let async_closure = hir.parent_id(parent_hir_id);
                 if let hir::Node::Expr(hir::Expr {
                     kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
                     ..
@@ -668,7 +668,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
             if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty)
-                && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
+                && !self.type_is_sized_modulo_regions(self.param_env, output_ty)
             {
                 let descr = match maybe_def {
                     DefIdOrName::DefId(def_id) => self.tcx.def_descr(def_id),
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 316c2a7eeeb..d28b3b3ce7b 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -96,7 +96,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let t = self.resolve_vars_if_possible(t);
         t.error_reported()?;
 
-        if self.type_is_sized_modulo_regions(self.param_env, t, span) {
+        if self.type_is_sized_modulo_regions(self.param_env, t) {
             return Ok(Some(PointerKind::Thin));
         }
 
@@ -722,7 +722,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
         debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
 
-        if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span)
+        if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty)
             && !self.cast_ty.has_infer_types()
         {
             self.report_cast_to_unsized_type(fcx);
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 773ac0e40c5..ec391ea80f4 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -2,13 +2,12 @@
 
 use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
 
-use hir::def::DefKind;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::LateBoundRegionConversionTime;
+use rustc_infer::infer::{DefineOpaqueTypes, LateBoundRegionConversionTime};
 use rustc_infer::infer::{InferOk, InferResult};
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::ty::subst::InternalSubsts;
@@ -563,10 +562,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ) {
                 // Check that E' = S'.
                 let cause = self.misc(hir_ty.span);
-                let InferOk { value: (), obligations } = self
-                    .at(&cause, self.param_env)
-                    .define_opaque_types(true)
-                    .eq(*expected_ty, supplied_ty)?;
+                let InferOk { value: (), obligations } = self.at(&cause, self.param_env).eq(
+                    DefineOpaqueTypes::Yes,
+                    *expected_ty,
+                    supplied_ty,
+                )?;
                 all_obligations.extend(obligations);
             }
 
@@ -576,10 +576,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 supplied_sig.output(),
             );
             let cause = &self.misc(decl.output.span());
-            let InferOk { value: (), obligations } = self
-                .at(cause, self.param_env)
-                .define_opaque_types(true)
-                .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?;
+            let InferOk { value: (), obligations } = self.at(cause, self.param_env).eq(
+                DefineOpaqueTypes::Yes,
+                expected_sigs.liberated_sig.output(),
+                supplied_output_ty,
+            )?;
             all_obligations.extend(obligations);
 
             let inputs = inputs.into_iter().map(|ty| self.resolve_vars_if_possible(ty));
@@ -713,14 +714,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .subst_iter_copied(self.tcx, substs)
                 .find_map(|(p, s)| get_future_output(p, s))?,
             ty::Error(_) => return None,
-            ty::Alias(ty::Projection, proj)
-                if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder =>
-            {
-                self.tcx
-                    .bound_explicit_item_bounds(proj.def_id)
-                    .subst_iter_copied(self.tcx, proj.substs)
-                    .find_map(|(p, s)| get_future_output(p, s))?
-            }
+            ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self
+                .tcx
+                .bound_explicit_item_bounds(proj.def_id)
+                .subst_iter_copied(self.tcx, proj.substs)
+                .find_map(|(p, s)| get_future_output(p, s))?,
             _ => span_bug!(
                 self.tcx.def_span(expr_def_id),
                 "async fn generator return type not an inference variable: {ret_ty}"
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 00b86890b33..8fa3bcd68c3 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -45,8 +45,8 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::Expr;
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{Coercion, InferOk, InferResult};
-use rustc_infer::traits::Obligation;
+use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
+use rustc_infer::traits::{Obligation, PredicateObligation};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -143,11 +143,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
     fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
         debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
         self.commit_if_ok(|_| {
-            let at = self.at(&self.cause, self.fcx.param_env).define_opaque_types(true);
+            let at = self.at(&self.cause, self.fcx.param_env);
             if self.use_lub {
-                at.lub(b, a)
+                at.lub(DefineOpaqueTypes::Yes, b, a)
             } else {
-                at.sup(b, a)
+                at.sup(DefineOpaqueTypes::Yes, b, a)
                     .map(|InferOk { value: (), obligations }| InferOk { value: a, obligations })
             }
         })
@@ -175,7 +175,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             // so this will have the side-effect of making sure we have no ambiguities
             // due to `[type error]` and `_` not coercing together.
             let _ = self.commit_if_ok(|_| {
-                self.at(&self.cause, self.param_env).define_opaque_types(true).eq(a, b)
+                self.at(&self.cause, self.param_env).eq(DefineOpaqueTypes::Yes, a, b)
             });
             return success(vec![], self.fcx.tcx.ty_error(guar), vec![]);
         }
@@ -597,13 +597,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         // and almost never more than 3. By using a SmallVec we avoid an
         // allocation, at the (very small) cost of (occasionally) having to
         // shift subsequent elements down when removing the front element.
-        let mut queue: SmallVec<[_; 4]> = smallvec![traits::predicate_for_trait_def(
+        let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new(
             self.tcx,
-            self.fcx.param_env,
             cause,
-            coerce_unsized_did,
-            0,
-            [coerce_source, coerce_target]
+            self.fcx.param_env,
+            self.tcx.mk_trait_ref(coerce_unsized_did, [coerce_source, coerce_target])
         )];
 
         let mut has_unsized_tuple_coercion = false;
@@ -651,9 +649,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                         let self_ty = trait_pred.skip_binder().self_ty();
                         let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty();
                         debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred);
-                        match (&self_ty.kind(), &unsize_ty.kind()) {
-                            (ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
-                                if self.type_var_is_sized(*v) =>
+                        match (self_ty.kind(), unsize_ty.kind()) {
+                            (&ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
+                                if self.type_var_is_sized(v) =>
                             {
                                 debug!("coerce_unsized: have sized infer {:?}", v);
                                 coercion.obligations.push(obligation);
@@ -1101,9 +1099,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     (ty::FnDef(..), ty::FnDef(..)) => {
                         // Don't reify if the function types have a LUB, i.e., they
                         // are the same function and their parameters have a LUB.
-                        match self
-                            .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
-                        {
+                        match self.commit_if_ok(|_| {
+                            self.at(cause, self.param_env).lub(
+                                DefineOpaqueTypes::No,
+                                prev_ty,
+                                new_ty,
+                            )
+                        }) {
                             // We have a LUB of prev_ty and new_ty, just return it.
                             Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)),
                             Err(_) => {
@@ -1153,7 +1155,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let sig = self
                 .at(cause, self.param_env)
                 .trace(prev_ty, new_ty)
-                .lub(a_sig, b_sig)
+                .lub(DefineOpaqueTypes::No, a_sig, b_sig)
                 .map(|ok| self.register_infer_ok_obligations(ok))?;
 
             // Reify both sides and return the reified fn pointer type.
@@ -1237,7 +1239,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
 
                 return self
-                    .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
+                    .commit_if_ok(|_| {
+                        self.at(cause, self.param_env).lub(DefineOpaqueTypes::No, prev_ty, new_ty)
+                    })
                     .map(|ok| self.register_infer_ok_obligations(ok));
             }
         }
@@ -1248,8 +1252,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if let Some(e) = first_error {
                     Err(e)
                 } else {
-                    self.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
-                        .map(|ok| self.register_infer_ok_obligations(ok))
+                    self.commit_if_ok(|_| {
+                        self.at(cause, self.param_env).lub(DefineOpaqueTypes::No, prev_ty, new_ty)
+                    })
+                    .map(|ok| self.register_infer_ok_obligations(ok))
                 }
             }
             Ok(ok) => {
@@ -1487,8 +1493,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             assert!(expression_ty.is_unit(), "if let hack without unit type");
             fcx.at(cause, fcx.param_env)
                 // needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
-                .define_opaque_types(true)
-                .eq_exp(label_expression_as_expected, expression_ty, self.merged_ty())
+                .eq_exp(
+                    DefineOpaqueTypes::Yes,
+                    label_expression_as_expected,
+                    expression_ty,
+                    self.merged_ty(),
+                )
                 .map(|infer_ok| {
                     fcx.register_infer_ok_obligations(infer_ok);
                     expression_ty
@@ -1710,12 +1720,13 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
                 }
             }
-            fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
+            fcx.get_node_fn_decl(parent)
+                .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
         } else {
             fcx.get_fn_decl(parent_id)
         };
 
-        if let Some((fn_decl, can_suggest)) = fn_decl {
+        if let Some((fn_id, fn_decl, can_suggest)) = fn_decl {
             if blk_id.is_none() {
                 pointing_at_return_type |= fcx.suggest_missing_return_type(
                     &mut err,
@@ -1723,7 +1734,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     expected,
                     found,
                     can_suggest,
-                    fcx.tcx.hir().get_parent_item(id).into(),
+                    fn_id,
                 );
             }
             if !pointing_at_return_type {
@@ -1734,17 +1745,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         let parent_id = fcx.tcx.hir().get_parent_item(id);
         let parent_item = fcx.tcx.hir().get_by_def_id(parent_id.def_id);
 
-        if let (Some(expr), Some(_), Some((fn_decl, _, _))) =
+        if let (Some(expr), Some(_), Some((fn_id, fn_decl, _, _))) =
             (expression, blk_id, fcx.get_node_fn_decl(parent_item))
         {
             fcx.suggest_missing_break_or_return_expr(
-                &mut err,
-                expr,
-                fn_decl,
-                expected,
-                found,
-                id,
-                parent_id.into(),
+                &mut err, expr, fn_decl, expected, found, id, fn_id,
             );
         }
 
@@ -1870,7 +1875,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
     }
 
     fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
-        if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id)
+        if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id)
             && let hir::FnRetTy::Return(ty) = fn_decl.output
             && let ty = fcx.astconv().ast_ty_to_ty( ty)
             && let ty::Dynamic(..) = ty.kind()
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 7ba57b3b7a2..06e857ec3ca 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -8,7 +8,7 @@ use rustc_hir::def::CtorKind;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{is_range_literal, Node};
-use rustc_infer::infer::InferOk;
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
@@ -83,7 +83,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.annotate_expected_due_to_let_ty(err, expr, error);
         self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error);
         self.note_type_is_not_clone(err, expected, expr_ty, expr);
-        self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
+        self.note_internal_mutation_in_method(err, expr, Some(expected), expr_ty);
         self.check_for_range_as_method_call(err, expr, expr_ty, expected);
         self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
         self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty);
@@ -113,7 +113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         actual: Ty<'tcx>,
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
-        match self.at(cause, self.param_env).define_opaque_types(true).sup(expected, actual) {
+        match self.at(cause, self.param_env).sup(DefineOpaqueTypes::Yes, expected, actual) {
             Ok(InferOk { obligations, value: () }) => {
                 self.register_predicates(obligations);
                 None
@@ -143,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         actual: Ty<'tcx>,
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
-        match self.at(cause, self.param_env).define_opaque_types(true).eq(expected, actual) {
+        match self.at(cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, actual) {
             Ok(InferOk { obligations, value: () }) => {
                 self.register_predicates(obligations);
                 None
@@ -1480,7 +1480,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                     // For this suggestion to make sense, the type would need to be `Copy`,
                     // or we have to be moving out of a `Box<T>`
-                    if self.type_is_copy_modulo_regions(self.param_env, expected, sp)
+                    if self.type_is_copy_modulo_regions(self.param_env, expected)
                         // FIXME(compiler-errors): We can actually do this if the checked_ty is
                         // `steps` layers of boxes, not just one, but this is easier and most likely.
                         || (checked_ty.is_box() && steps == 1)
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 7fc4ccb04ee..29db16849dd 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -36,6 +36,7 @@ use rustc_hir_analysis::astconv::AstConv as _;
 use rustc_hir_analysis::check::ty_kind_suggestion;
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::InferOk;
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::middle::stability;
@@ -283,7 +284,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let tcx = self.tcx;
         match expr.kind {
-            ExprKind::Box(subexpr) => self.check_expr_box(subexpr, expected),
             ExprKind::Lit(ref lit) => self.check_lit(&lit, expected),
             ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected),
             ExprKind::Assign(lhs, rhs, span) => {
@@ -358,16 +358,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn check_expr_box(&self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>) -> Ty<'tcx> {
-        let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| match ty.kind() {
-            ty::Adt(def, _) if def.is_box() => Expectation::rvalue_hint(self, ty.boxed_ty()),
-            _ => NoExpectation,
-        });
-        let referent_ty = self.check_expr_with_expectation(expr, expected_inner);
-        self.require_type_is_sized(referent_ty, expr.span, traits::SizedBoxType);
-        self.tcx.mk_box(referent_ty)
-    }
-
     fn check_expr_unary(
         &self,
         unop: hir::UnOp,
@@ -798,7 +788,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.ret_coercion_span.set(Some(expr.span));
             }
             let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
-            if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
+            if let Some((_, fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
                 coercion.coerce_forced_unit(
                     self,
                     &cause,
@@ -1683,7 +1673,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             if let Some(_) = remaining_fields.remove(&ident) {
                                 let target_ty = self.field_ty(base_expr.span, f, substs);
                                 let cause = self.misc(base_expr.span);
-                                match self.at(&cause, self.param_env).sup(target_ty, fru_ty) {
+                                match self.at(&cause, self.param_env).sup(
+                                    DefineOpaqueTypes::No,
+                                    target_ty,
+                                    fru_ty,
+                                ) {
                                     Ok(InferOk { obligations, value: () }) => {
                                         self.register_predicates(obligations)
                                     }
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index b9a058d6bba..c62c1553d6f 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -356,10 +356,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                 self.walk_captures(closure);
             }
 
-            hir::ExprKind::Box(ref base) => {
-                self.consume_expr(base);
-            }
-
             hir::ExprKind::Yield(value, _) => {
                 self.consume_expr(value);
             }
@@ -871,10 +867,7 @@ fn copy_or_move<'a, 'tcx>(
     mc: &mc::MemCategorizationContext<'a, 'tcx>,
     place_with_id: &PlaceWithHirId<'tcx>,
 ) -> ConsumeMode {
-    if !mc.type_is_copy_modulo_regions(
-        place_with_id.place.ty(),
-        mc.tcx().hir().span(place_with_id.hir_id),
-    ) {
+    if !mc.type_is_copy_modulo_regions(place_with_id.place.ty()) {
         ConsumeMode::Move
     } else {
         ConsumeMode::Copy
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 2075537cad7..8455076de56 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -19,7 +19,7 @@ use rustc_hir_analysis::astconv::{
 };
 use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
-use rustc_infer::infer::InferResult;
+use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
@@ -558,7 +558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let span = self.tcx.hir().body(body_id).value.span;
             let ok = self
                 .at(&self.misc(span), self.param_env)
-                .eq(interior, witness)
+                .eq(DefineOpaqueTypes::No, interior, witness)
                 .expect("Failed to unify generator interior type");
             let mut obligations = ok.obligations;
 
@@ -898,56 +898,74 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         )
     }
 
-    /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
+    /// Given a function `Node`, return its  `HirId` and `FnDecl` if it exists. Given a closure
+    /// that is the child of a function, return that function's `HirId` and `FnDecl` instead.
+    /// This may seem confusing at first, but this is used in diagnostics for `async fn`,
+    /// for example, where most of the type checking actually happens within a nested closure,
+    /// but we often want access to the parent function's signature.
+    ///
+    /// Otherwise, return false.
     pub(in super::super) fn get_node_fn_decl(
         &self,
         node: Node<'tcx>,
-    ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> {
+    ) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> {
         match node {
-            Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => {
+            Node::Item(&hir::Item {
+                ident,
+                kind: hir::ItemKind::Fn(ref sig, ..),
+                owner_id,
+                ..
+            }) => {
                 // This is less than ideal, it will not suggest a return type span on any
                 // method called `main`, regardless of whether it is actually the entry point,
                 // but it will still present it as the reason for the expected type.
-                Some((&sig.decl, ident, ident.name != sym::main))
+                Some((
+                    hir::HirId::make_owner(owner_id.def_id),
+                    &sig.decl,
+                    ident,
+                    ident.name != sym::main,
+                ))
             }
             Node::TraitItem(&hir::TraitItem {
                 ident,
                 kind: hir::TraitItemKind::Fn(ref sig, ..),
+                owner_id,
                 ..
-            }) => Some((&sig.decl, ident, true)),
+            }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, true)),
             Node::ImplItem(&hir::ImplItem {
                 ident,
                 kind: hir::ImplItemKind::Fn(ref sig, ..),
+                owner_id,
                 ..
-            }) => Some((&sig.decl, ident, false)),
-            Node::Expr(&hir::Expr {
-                hir_id,
-                kind: hir::ExprKind::Closure(..),
-                ..
-            }) if let Some(Node::Expr(&hir::Expr {
-                hir_id,
-                kind: hir::ExprKind::Call(..),
-                ..
-            })) = self.tcx.hir().find_parent(hir_id) &&
-            let Some(Node::Item(&hir::Item {
+            }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)),
+            Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(..), .. })
+                if let Some(Node::Item(&hir::Item {
+                    ident,
+                    kind: hir::ItemKind::Fn(ref sig, ..),
+                    owner_id,
+                    ..
+                })) = self.tcx.hir().find_parent(hir_id) => Some((
+                hir::HirId::make_owner(owner_id.def_id),
+                &sig.decl,
                 ident,
-                kind: hir::ItemKind::Fn(ref sig, ..),
-                ..
-            })) = self.tcx.hir().find_parent(hir_id) => {
-                Some((&sig.decl, ident, ident.name != sym::main))
-            },
+                ident.name != sym::main,
+            )),
             _ => None,
         }
     }
 
-    /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a
+    /// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
     /// suggestion can be made, `None` otherwise.
-    pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> {
+    pub fn get_fn_decl(
+        &self,
+        blk_id: hir::HirId,
+    ) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, bool)> {
         // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
         // `while` before reaching it, as block tail returns are not available in them.
         self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
             let parent = self.tcx.hir().get(blk_id);
-            self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
+            self.get_node_fn_decl(parent)
+                .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
         })
     }
 
@@ -955,44 +973,75 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         err: &mut Diagnostic,
         expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
+        expected: Option<Ty<'tcx>>,
         found: Ty<'tcx>,
     ) {
         if found != self.tcx.types.unit {
             return;
         }
-        if let ExprKind::MethodCall(path_segment, rcvr, ..) = expr.kind {
-            if self
-                .typeck_results
+
+        let ExprKind::MethodCall(path_segment, rcvr, ..) = expr.kind else {
+            return;
+        };
+
+        let rcvr_has_the_expected_type = self
+            .typeck_results
+            .borrow()
+            .expr_ty_adjusted_opt(rcvr)
+            .and_then(|ty| expected.map(|expected_ty| expected_ty.peel_refs() == ty.peel_refs()))
+            .unwrap_or(false);
+
+        let prev_call_mutates_and_returns_unit = || {
+            self.typeck_results
                 .borrow()
-                .expr_ty_adjusted_opt(rcvr)
-                .map_or(true, |ty| expected.peel_refs() != ty.peel_refs())
-            {
-                return;
-            }
-            let mut sp = MultiSpan::from_span(path_segment.ident.span);
-            sp.push_span_label(
-                path_segment.ident.span,
-                format!(
-                    "this call modifies {} in-place",
-                    match rcvr.kind {
-                        ExprKind::Path(QPath::Resolved(
-                            None,
-                            hir::Path { segments: [segment], .. },
-                        )) => format!("`{}`", segment.ident),
-                        _ => "its receiver".to_string(),
-                    }
-                ),
-            );
+                .type_dependent_def_id(expr.hir_id)
+                .map(|def_id| self.tcx.fn_sig(def_id).skip_binder().skip_binder())
+                .and_then(|sig| sig.inputs_and_output.split_last())
+                .map(|(output, inputs)| {
+                    output.is_unit()
+                        && inputs
+                            .get(0)
+                            .and_then(|self_ty| self_ty.ref_mutability())
+                            .map_or(false, rustc_ast::Mutability::is_mut)
+                })
+                .unwrap_or(false)
+        };
+
+        if !(rcvr_has_the_expected_type || prev_call_mutates_and_returns_unit()) {
+            return;
+        }
+
+        let mut sp = MultiSpan::from_span(path_segment.ident.span);
+        sp.push_span_label(
+            path_segment.ident.span,
+            format!(
+                "this call modifies {} in-place",
+                match rcvr.kind {
+                    ExprKind::Path(QPath::Resolved(
+                        None,
+                        hir::Path { segments: [segment], .. },
+                    )) => format!("`{}`", segment.ident),
+                    _ => "its receiver".to_string(),
+                }
+            ),
+        );
+
+        let modifies_rcvr_note =
+            format!("method `{}` modifies its receiver in-place", path_segment.ident);
+        if rcvr_has_the_expected_type {
             sp.push_span_label(
                 rcvr.span,
                 "you probably want to use this value after calling the method...",
             );
+            err.span_note(sp, &modifies_rcvr_note);
+            err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident));
+        } else if let ExprKind::MethodCall(..) = rcvr.kind {
             err.span_note(
                 sp,
-                &format!("method `{}` modifies its receiver in-place", path_segment.ident),
+                modifies_rcvr_note.clone() + ", it is not meant to be used in method chains.",
             );
-            err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident));
+        } else {
+            err.span_note(sp, &modifies_rcvr_note);
         }
     }
 
@@ -1315,7 +1364,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // This also occurs for an enum variant on a type alias.
             let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).subst(tcx, substs));
             let self_ty = self.normalize(span, self_ty);
-            match self.at(&self.misc(span), self.param_env).eq(impl_ty, self_ty) {
+            match self.at(&self.misc(span), self.param_env).eq(
+                DefineOpaqueTypes::No,
+                impl_ty,
+                self_ty,
+            ) {
                 Ok(ok) => self.register_infer_ok_obligations(ok),
                 Err(_) => {
                     self.tcx.sess.delay_span_bug(
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index ea54b76bdec..61338ac613a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -24,8 +24,8 @@ use rustc_hir_analysis::structured_errors::StructuredDiagnostic;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::InferOk;
 use rustc_infer::infer::TypeTrace;
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, IsSuggestable, Ty};
@@ -301,9 +301,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             // 3. Check if the formal type is a supertype of the checked one
             //    and register any such obligations for future type checks
-            let supertype_error = self
-                .at(&self.misc(provided_arg.span), self.param_env)
-                .sup(formal_input_ty, coerced_ty);
+            let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup(
+                DefineOpaqueTypes::No,
+                formal_input_ty,
+                coerced_ty,
+            );
             let subtyping_error = match supertype_error {
                 Ok(InferOk { obligations, value: () }) => {
                     self.register_predicates(obligations);
@@ -585,7 +587,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             // Using probe here, since we don't want this subtyping to affect inference.
             let subtyping_error = self.probe(|_| {
-                self.at(&self.misc(arg_span), self.param_env).sup(formal_input_ty, coerced_ty).err()
+                self.at(&self.misc(arg_span), self.param_env)
+                    .sup(DefineOpaqueTypes::No, formal_input_ty, coerced_ty)
+                    .err()
             });
 
             // Same as above: if either the coerce type or the checked type is an error type,
@@ -1665,7 +1669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
     fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
         let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
-        self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
+        self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident))
     }
 
     /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 1dea3e6f900..c6fd0b61035 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -211,13 +211,13 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
     fn get_type_parameter_bounds(
         &self,
         _: Span,
-        def_id: DefId,
+        def_id: LocalDefId,
         _: Ident,
     ) -> ty::GenericPredicates<'tcx> {
         let tcx = self.tcx;
-        let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
+        let item_def_id = tcx.hir().ty_param_owner(def_id);
         let generics = tcx.generics_of(item_def_id);
-        let index = generics.param_def_id_to_index[&def_id];
+        let index = generics.param_def_id_to_index[&def_id.to_def_id()];
         ty::GenericPredicates {
             parent: None,
             predicates: tcx.arena.alloc_from_iter(
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 690d8a23826..7273b93b676 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -64,8 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let expr = expr.peel_drop_temps();
         self.suggest_missing_semicolon(err, expr, expected, false);
         let mut pointing_at_return_type = false;
-        if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
-            let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap();
+        if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
             pointing_at_return_type = self.suggest_missing_return_type(
                 err,
                 &fn_decl,
@@ -1012,11 +1011,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut suggest_copied_or_cloned = || {
             let expr_inner_ty = substs.type_at(0);
             let expected_inner_ty = expected_substs.type_at(0);
-            if let ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
-                && self.can_eq(self.param_env, *ty, expected_inner_ty)
+            if let &ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
+                && self.can_eq(self.param_env, ty, expected_inner_ty)
             {
                 let def_path = self.tcx.def_path_str(adt_def.did());
-                if self.type_is_copy_modulo_regions(self.param_env, *ty, expr.span) {
+                if self.type_is_copy_modulo_regions(self.param_env, ty) {
                     diag.span_suggestion_verbose(
                         expr.span.shrink_to_hi(),
                         format!(
@@ -1030,9 +1029,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
                         self,
                         self.param_env,
-                        *ty,
+                        ty,
                         clone_did,
-                        expr.span
                     )
                 {
                     diag.span_suggestion_verbose(
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index 7c0402b1c7f..1eeb7d984ee 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -190,7 +190,6 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
             //
             // Some of these may be interesting in the future
             ExprKind::Path(..)
-            | ExprKind::Box(..)
             | ExprKind::ConstBlock(..)
             | ExprKind::Array(..)
             | ExprKind::Call(..)
@@ -478,7 +477,6 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
             | ExprKind::AssignOp(..)
             | ExprKind::Binary(..)
             | ExprKind::Block(..)
-            | ExprKind::Box(..)
             | ExprKind::Cast(..)
             | ExprKind::Closure { .. }
             | ExprKind::ConstBlock(..)
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 2e41c2041f8..9ecc870a70d 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -13,7 +13,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::HirIdSet;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
-use rustc_infer::infer::RegionVariableOrigin;
+use rustc_infer::infer::{DefineOpaqueTypes, RegionVariableOrigin};
 use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
 use rustc_middle::ty::fold::FnMutDelegate;
 use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitableExt};
@@ -327,7 +327,11 @@ pub fn resolve_interior<'a, 'tcx>(
     );
 
     // Unify the type variable inside the generator with the new witness
-    match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(interior, witness) {
+    match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(
+        DefineOpaqueTypes::No,
+        interior,
+        witness,
+    ) {
         Ok(ok) => fcx.register_infer_ok_obligations(ok),
         _ => bug!("failed to relate {interior} and {witness}"),
     }
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index d9c56134b66..6af095cb4d4 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -207,7 +207,7 @@ fn typeck_with_fallback<'tcx>(
     let body = tcx.hir().body(body_id);
 
     let param_env = tcx.param_env(def_id);
-    let param_env = if tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) {
+    let param_env = if tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
         param_env.without_const()
     } else {
         param_env
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 4d3969d28aa..95e5483abf3 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -120,8 +120,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         self.infcx.tcx
     }
 
-    pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
-        self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span)
+    pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
+        self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
     }
 
     fn resolve_vars_if_possible<T>(&self, value: T) -> T
@@ -382,7 +382,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             | hir::ExprKind::Struct(..)
             | hir::ExprKind::Repeat(..)
             | hir::ExprKind::InlineAsm(..)
-            | hir::ExprKind::Box(..)
             | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 169f128e0a0..a0aa43deadc 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -8,7 +8,7 @@ use rustc_hir_analysis::astconv::generics::{
     check_generic_arg_count_for_call, create_substs_for_generic_args,
 };
 use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
-use rustc_infer::infer::{self, InferOk};
+use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
 use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
 use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
@@ -478,7 +478,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                 substs,
             })),
         );
-        match self.at(&cause, self.param_env).sup(method_self_ty, self_ty) {
+        match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::No, method_self_ty, self_ty) {
             Ok(InferOk { obligations, value: () }) => {
                 self.register_predicates(obligations);
             }
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 3254a930342..b6d39341fe7 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -13,6 +13,7 @@ use rustc_hir_analysis::astconv::InferCtxtExt as _;
 use rustc_hir_analysis::autoderef::{self, Autoderef};
 use rustc_infer::infer::canonical::OriginalQueryValues;
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
+use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
 use rustc_middle::middle::stability;
 use rustc_middle::ty::fast_reject::TreatProjections;
@@ -930,7 +931,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 if let Some(self_ty) = self_ty {
                     if self
                         .at(&ObligationCause::dummy(), self.param_env)
-                        .sup(fty.inputs()[0], self_ty)
+                        .sup(DefineOpaqueTypes::No, fty.inputs()[0], self_ty)
                         .is_err()
                     {
                         return false;
@@ -1027,6 +1028,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     true
                 }
             })
+            // ensure that we don't suggest unstable methods
+            .filter(|candidate| {
+                // note that `DUMMY_SP` is ok here because it is only used for
+                // suggestions and macro stuff which isn't applicable here.
+                !matches!(
+                    self.tcx.eval_stability(candidate.item.def_id, None, DUMMY_SP, None),
+                    stability::EvalResult::Deny { .. }
+                )
+            })
             .map(|candidate| candidate.item.ident(self.tcx))
             .filter(|&name| set.insert(name))
             .collect();
@@ -1436,9 +1446,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 CandidateSource::Trait(candidate.item.container_id(self.tcx))
             }
             TraitCandidate(trait_ref) => self.probe(|_| {
-                let _ = self
-                    .at(&ObligationCause::dummy(), self.param_env)
-                    .sup(candidate.xform_self_ty, self_ty);
+                let _ = self.at(&ObligationCause::dummy(), self.param_env).sup(
+                    DefineOpaqueTypes::No,
+                    candidate.xform_self_ty,
+                    self_ty,
+                );
                 match self.select_trait_candidate(trait_ref) {
                     Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
                         // If only a single impl matches, make the error message point
@@ -1465,10 +1477,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
         self.probe(|_| {
             // First check that the self type can be related.
-            let sub_obligations = match self
-                .at(&ObligationCause::dummy(), self.param_env)
-                .sup(probe.xform_self_ty, self_ty)
-            {
+            let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env).sup(
+                DefineOpaqueTypes::No,
+                probe.xform_self_ty,
+                self_ty,
+            ) {
                 Ok(InferOk { obligations, value: () }) => obligations,
                 Err(err) => {
                     debug!("--> cannot relate self-types {:?}", err);
@@ -1683,7 +1696,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 if let ProbeResult::Match = result
                     && self
                     .at(&ObligationCause::dummy(), self.param_env)
-                    .sup(return_ty, xform_ret_ty)
+                    .sup(DefineOpaqueTypes::No, return_ty, xform_ret_ty)
                     .is_err()
                 {
                     result = ProbeResult::BadReturnType;
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 7055d9257ec..50f2b71250c 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -416,6 +416,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
                 probe.is_ok()
             });
+
+            self.note_internal_mutation_in_method(
+                &mut err,
+                rcvr_expr,
+                expected.to_option(&self),
+                rcvr_ty,
+            );
         }
 
         let mut custom_span_label = false;
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 37783bc91bb..8a83bb58573 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -21,7 +21,7 @@ use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{self, FulfillmentError};
+use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
 use rustc_type_ir::sty::TyKind::*;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -434,7 +434,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     if self.type_is_copy_modulo_regions(
                         self.param_env,
                         *lhs_deref_ty,
-                        lhs_expr.span,
                     ) {
                         suggest_deref_binop(*lhs_deref_ty);
                     }
@@ -776,7 +775,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             (None, Some(trait_did)) => {
                 let (obligation, _) =
                     self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types));
-                Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation))
+                // FIXME: This should potentially just add the obligation to the `FnCtxt`
+                let ocx = ObligationCtxt::new(&self.infcx);
+                ocx.register_obligation(obligation);
+                Err(ocx.select_all_or_error())
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 4a432328c4d..d5d260d7138 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -424,7 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // closures. We want to make sure any adjustment that might make us move the place into
                 // the closure gets handled.
                 let (place, capture_kind) =
-                    restrict_precision_for_drop_types(self, place, capture_kind, usage_span);
+                    restrict_precision_for_drop_types(self, place, capture_kind);
 
                 capture_info.capture_kind = capture_kind;
                 (place, capture_info)
@@ -1498,7 +1498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     fn should_log_capture_analysis(&self, closure_def_id: LocalDefId) -> bool {
-        self.tcx.has_attr(closure_def_id.to_def_id(), sym::rustc_capture_analysis)
+        self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis)
     }
 
     fn log_capture_analysis_first_pass(
@@ -1822,9 +1822,8 @@ fn restrict_precision_for_drop_types<'a, 'tcx>(
     fcx: &'a FnCtxt<'a, 'tcx>,
     mut place: Place<'tcx>,
     mut curr_mode: ty::UpvarCapture,
-    span: Span,
 ) -> (Place<'tcx>, ty::UpvarCapture) {
-    let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span);
+    let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty());
 
     if let (false, UpvarCapture::ByValue) = (is_copy_type, curr_mode) {
         for i in 0..place.projections.len() {
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index af588b16d59..e876fa27593 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -44,8 +44,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // This attribute causes us to dump some writeback information
         // in the form of errors, which is used for unit tests.
-        let rustc_dump_user_substs =
-            self.tcx.has_attr(item_def_id.to_def_id(), sym::rustc_dump_user_substs);
+        let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs);
 
         let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs);
         for param in body.params {
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index b839416c919..1d88dfd20c8 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -371,7 +371,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
     fn check_item(&mut self, item_id: LocalDefId) {
         let item_span = self.tcx.def_span(item_id.to_def_id());
         let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id());
-        for attr in self.tcx.get_attrs(item_id.to_def_id(), sym::rustc_clean) {
+        for attr in self.tcx.get_attrs(item_id, sym::rustc_clean) {
             let Some(assertion) = self.assertion_maybe(item_id, attr) else {
                 continue;
             };
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 7d9bae735e5..0c8854e962a 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -30,16 +30,20 @@ use super::*;
 use rustc_middle::ty::relate::{Relate, TypeRelation};
 use rustc_middle::ty::{Const, ImplSubject};
 
+/// Whether we should define opaque types or just treat them opaquely.
+///
+/// Currently only used to prevent predicate matching from matching anything
+/// against opaque types.
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum DefineOpaqueTypes {
+    Yes,
+    No,
+}
+
 pub struct At<'a, 'tcx> {
     pub infcx: &'a InferCtxt<'tcx>,
     pub cause: &'a ObligationCause<'tcx>,
     pub param_env: ty::ParamEnv<'tcx>,
-    /// Whether we should define opaque types
-    /// or just treat them opaquely.
-    /// Currently only used to prevent predicate
-    /// matching from matching anything against opaque
-    /// types.
-    pub define_opaque_types: bool,
 }
 
 pub struct Trace<'a, 'tcx> {
@@ -55,7 +59,7 @@ impl<'tcx> InferCtxt<'tcx> {
         cause: &'a ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> At<'a, 'tcx> {
-        At { infcx: self, cause, param_env, define_opaque_types: false }
+        At { infcx: self, cause, param_env }
     }
 
     /// Forks the inference context, creating a new inference context with the same inference
@@ -84,7 +88,6 @@ impl<'tcx> InferCtxt<'tcx> {
 
 pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
     fn to_trace(
-        tcx: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -93,33 +96,21 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
 }
 
 impl<'a, 'tcx> At<'a, 'tcx> {
-    pub fn define_opaque_types(self, define_opaque_types: bool) -> Self {
-        Self { define_opaque_types, ..self }
-    }
-
-    /// Hacky routine for equating two impl headers in coherence.
-    pub fn eq_impl_headers(
-        self,
-        expected: &ty::ImplHeader<'tcx>,
-        actual: &ty::ImplHeader<'tcx>,
-    ) -> InferResult<'tcx, ()> {
-        debug!("eq_impl_header({:?} = {:?})", expected, actual);
-        match (expected.trait_ref, actual.trait_ref) {
-            (Some(a_ref), Some(b_ref)) => self.eq(a_ref, b_ref),
-            (None, None) => self.eq(expected.self_ty, actual.self_ty),
-            _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
-        }
-    }
-
     /// Makes `a <: b`, where `a` may or may not be expected.
     ///
     /// See [`At::trace_exp`] and [`Trace::sub`] for a version of
     /// this method that only requires `T: Relate<'tcx>`
-    pub fn sub_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()>
+    pub fn sub_exp<T>(
+        self,
+        define_opaque_types: DefineOpaqueTypes,
+        a_is_expected: bool,
+        a: T,
+        b: T,
+    ) -> InferResult<'tcx, ()>
     where
         T: ToTrace<'tcx>,
     {
-        self.trace_exp(a_is_expected, a, b).sub(a, b)
+        self.trace_exp(a_is_expected, a, b).sub(define_opaque_types, a, b)
     }
 
     /// Makes `actual <: expected`. For example, if type-checking a
@@ -129,54 +120,81 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     ///
     /// See [`At::trace`] and [`Trace::sub`] for a version of
     /// this method that only requires `T: Relate<'tcx>`
-    pub fn sup<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()>
+    pub fn sup<T>(
+        self,
+        define_opaque_types: DefineOpaqueTypes,
+        expected: T,
+        actual: T,
+    ) -> InferResult<'tcx, ()>
     where
         T: ToTrace<'tcx>,
     {
-        self.sub_exp(false, actual, expected)
+        self.sub_exp(define_opaque_types, false, actual, expected)
     }
 
     /// Makes `expected <: actual`.
     ///
     /// See [`At::trace`] and [`Trace::sub`] for a version of
     /// this method that only requires `T: Relate<'tcx>`
-    pub fn sub<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()>
+    pub fn sub<T>(
+        self,
+        define_opaque_types: DefineOpaqueTypes,
+        expected: T,
+        actual: T,
+    ) -> InferResult<'tcx, ()>
     where
         T: ToTrace<'tcx>,
     {
-        self.sub_exp(true, expected, actual)
+        self.sub_exp(define_opaque_types, true, expected, actual)
     }
 
     /// Makes `expected <: actual`.
     ///
     /// See [`At::trace_exp`] and [`Trace::eq`] for a version of
     /// this method that only requires `T: Relate<'tcx>`
-    pub fn eq_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()>
+    pub fn eq_exp<T>(
+        self,
+        define_opaque_types: DefineOpaqueTypes,
+        a_is_expected: bool,
+        a: T,
+        b: T,
+    ) -> InferResult<'tcx, ()>
     where
         T: ToTrace<'tcx>,
     {
-        self.trace_exp(a_is_expected, a, b).eq(a, b)
+        self.trace_exp(a_is_expected, a, b).eq(define_opaque_types, a, b)
     }
 
     /// Makes `expected <: actual`.
     ///
     /// See [`At::trace`] and [`Trace::eq`] for a version of
     /// this method that only requires `T: Relate<'tcx>`
-    pub fn eq<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()>
+    pub fn eq<T>(
+        self,
+        define_opaque_types: DefineOpaqueTypes,
+        expected: T,
+        actual: T,
+    ) -> InferResult<'tcx, ()>
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).eq(expected, actual)
+        self.trace(expected, actual).eq(define_opaque_types, expected, actual)
     }
 
-    pub fn relate<T>(self, expected: T, variance: ty::Variance, actual: T) -> InferResult<'tcx, ()>
+    pub fn relate<T>(
+        self,
+        define_opaque_types: DefineOpaqueTypes,
+        expected: T,
+        variance: ty::Variance,
+        actual: T,
+    ) -> InferResult<'tcx, ()>
     where
         T: ToTrace<'tcx>,
     {
         match variance {
-            ty::Variance::Covariant => self.sub(expected, actual),
-            ty::Variance::Invariant => self.eq(expected, actual),
-            ty::Variance::Contravariant => self.sup(expected, actual),
+            ty::Variance::Covariant => self.sub(define_opaque_types, expected, actual),
+            ty::Variance::Invariant => self.eq(define_opaque_types, expected, actual),
+            ty::Variance::Contravariant => self.sup(define_opaque_types, expected, actual),
 
             // We could make this make sense but it's not readily
             // exposed and I don't feel like dealing with it. Note
@@ -195,11 +213,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     ///
     /// See [`At::trace`] and [`Trace::lub`] for a version of
     /// this method that only requires `T: Relate<'tcx>`
-    pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'tcx, T>
+    pub fn lub<T>(
+        self,
+        define_opaque_types: DefineOpaqueTypes,
+        expected: T,
+        actual: T,
+    ) -> InferResult<'tcx, T>
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).lub(expected, actual)
+        self.trace(expected, actual).lub(define_opaque_types, expected, actual)
     }
 
     /// Computes the greatest-lower-bound, or mutual subtype, of two
@@ -208,11 +231,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     ///
     /// See [`At::trace`] and [`Trace::glb`] for a version of
     /// this method that only requires `T: Relate<'tcx>`
-    pub fn glb<T>(self, expected: T, actual: T) -> InferResult<'tcx, T>
+    pub fn glb<T>(
+        self,
+        define_opaque_types: DefineOpaqueTypes,
+        expected: T,
+        actual: T,
+    ) -> InferResult<'tcx, T>
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).glb(expected, actual)
+        self.trace(expected, actual).glb(define_opaque_types, expected, actual)
     }
 
     /// Sets the "trace" values that will be used for
@@ -233,7 +261,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b);
+        let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
         Trace { at: self, trace, a_is_expected }
     }
 }
@@ -242,13 +270,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
     /// Makes `a <: b` where `a` may or may not be expected (if
     /// `a_is_expected` is true, then `a` is expected).
     #[instrument(skip(self), level = "debug")]
-    pub fn sub<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
+    pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
     where
         T: Relate<'tcx>,
     {
         let Trace { at, trace, a_is_expected } = self;
         at.infcx.commit_if_ok(|_| {
-            let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
+            let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
             fields
                 .sub(a_is_expected)
                 .relate(a, b)
@@ -259,13 +287,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
     /// Makes `a == b`; the expectation is set by the call to
     /// `trace()`.
     #[instrument(skip(self), level = "debug")]
-    pub fn eq<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
+    pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
     where
         T: Relate<'tcx>,
     {
         let Trace { at, trace, a_is_expected } = self;
         at.infcx.commit_if_ok(|_| {
-            let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
+            let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
             fields
                 .equate(a_is_expected)
                 .relate(a, b)
@@ -274,13 +302,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    pub fn lub<T>(self, a: T, b: T) -> InferResult<'tcx, T>
+    pub fn lub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
     where
         T: Relate<'tcx>,
     {
         let Trace { at, trace, a_is_expected } = self;
         at.infcx.commit_if_ok(|_| {
-            let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
+            let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
             fields
                 .lub(a_is_expected)
                 .relate(a, b)
@@ -289,13 +317,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    pub fn glb<T>(self, a: T, b: T) -> InferResult<'tcx, T>
+    pub fn glb<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
     where
         T: Relate<'tcx>,
     {
         let Trace { at, trace, a_is_expected } = self;
         at.infcx.commit_if_ok(|_| {
-            let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
+            let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
             fields
                 .glb(a_is_expected)
                 .relate(a, b)
@@ -306,7 +334,6 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
     fn to_trace(
-        tcx: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -314,10 +341,10 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
     ) -> TypeTrace<'tcx> {
         match (a, b) {
             (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
-                ToTrace::to_trace(tcx, cause, a_is_expected, trait_ref_a, trait_ref_b)
+                ToTrace::to_trace(cause, a_is_expected, trait_ref_a, trait_ref_b)
             }
             (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
-                ToTrace::to_trace(tcx, cause, a_is_expected, ty_a, ty_b)
+                ToTrace::to_trace(cause, a_is_expected, ty_a, ty_b)
             }
             (ImplSubject::Trait(_), ImplSubject::Inherent(_))
             | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
@@ -329,7 +356,6 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
     fn to_trace(
-        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -344,7 +370,6 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
     fn to_trace(
-        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -356,7 +381,6 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
     fn to_trace(
-        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -371,7 +395,6 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
     fn to_trace(
-        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -399,7 +422,6 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
     fn to_trace(
-        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -411,7 +433,6 @@ impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
     fn to_trace(
-        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -426,7 +447,6 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
     fn to_trace(
-        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -441,24 +461,17 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
     fn to_trace(
-        tcx: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
-        let a_ty = tcx.mk_projection(a.def_id, a.substs);
-        let b_ty = tcx.mk_projection(b.def_id, b.substs);
-        TypeTrace {
-            cause: cause.clone(),
-            values: Terms(ExpectedFound::new(a_is_expected, a_ty.into(), b_ty.into())),
-        }
+        TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) }
     }
 }
 
 impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
     fn to_trace(
-        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 436d29c2449..268896b671a 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -14,7 +14,7 @@ use crate::infer::canonical::{
 };
 use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
-use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
+use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
 use crate::traits::query::{Fallible, NoSolution};
 use crate::traits::{Obligation, ObligationCause, PredicateObligation};
 use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt};
@@ -159,9 +159,7 @@ impl<'tcx> InferCtxt<'tcx> {
             .opaque_type_storage
             .opaque_types
             .iter()
-            .map(|&(k, ref v)| {
-                (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)
-            })
+            .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty))
             .collect()
     }
 
@@ -510,7 +508,7 @@ impl<'tcx> InferCtxt<'tcx> {
             let b = substitute_value(self.tcx, &result_subst, b);
             debug!(?a, ?b, "constrain opaque type");
             obligations
-                .extend(self.at(cause, param_env).define_opaque_types(true).eq(a, b)?.obligations);
+                .extend(self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, a, b)?.obligations);
         }
 
         Ok(InferOk { value: result_subst, obligations })
@@ -603,8 +601,11 @@ impl<'tcx> InferCtxt<'tcx> {
 
                 match (value1.unpack(), value2.unpack()) {
                     (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => {
-                        obligations
-                            .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
+                        obligations.extend(
+                            self.at(cause, param_env)
+                                .eq(DefineOpaqueTypes::Yes, v1, v2)?
+                                .into_obligations(),
+                        );
                     }
                     (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
                         if re1.is_erased() && re2.is_erased() =>
@@ -612,11 +613,14 @@ impl<'tcx> InferCtxt<'tcx> {
                         // no action needed
                     }
                     (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => {
-                        obligations
-                            .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
+                        obligations.extend(
+                            self.at(cause, param_env)
+                                .eq(DefineOpaqueTypes::Yes, v1, v2)?
+                                .into_obligations(),
+                        );
                     }
                     (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
-                        let ok = self.at(cause, param_env).eq(v1, v2)?;
+                        let ok = self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, v1, v2)?;
                         obligations.extend(ok.into_obligations());
                     }
                     _ => {
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index a2332797e86..4503af03ca3 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -27,7 +27,7 @@ use super::glb::Glb;
 use super::lub::Lub;
 use super::sub::Sub;
 use super::type_variable::TypeVariableValue;
-use super::{InferCtxt, MiscVariable, TypeTrace};
+use super::{DefineOpaqueTypes, InferCtxt, MiscVariable, TypeTrace};
 use crate::traits::{Obligation, PredicateObligations};
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_hir::def_id::DefId;
@@ -52,12 +52,7 @@ pub struct CombineFields<'infcx, 'tcx> {
     pub cause: Option<ty::relate::Cause>,
     pub param_env: ty::ParamEnv<'tcx>,
     pub obligations: PredicateObligations<'tcx>,
-    /// Whether we should define opaque types
-    /// or just treat them opaquely.
-    /// Currently only used to prevent predicate
-    /// matching from matching anything against opaque
-    /// types.
-    pub define_opaque_types: bool,
+    pub define_opaque_types: DefineOpaqueTypes,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -194,10 +189,19 @@ impl<'tcx> InferCtxt<'tcx> {
         // the expected const's type. Specifically, we don't want const infer vars
         // to do any type shapeshifting before and after resolution.
         if let Err(guar) = compatible_types {
-            return Ok(self.tcx.const_error_with_guaranteed(
-                if relation.a_is_expected() { a.ty() } else { b.ty() },
-                guar,
-            ));
+            // HACK: equating both sides with `[const error]` eagerly prevents us
+            // from leaving unconstrained inference vars during things like impl
+            // matching in the solver.
+            let a_error = self.tcx.const_error_with_guaranteed(a.ty(), guar);
+            if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() {
+                return self.unify_const_variable(vid, a_error);
+            }
+            let b_error = self.tcx.const_error_with_guaranteed(b.ty(), guar);
+            if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() {
+                return self.unify_const_variable(vid, b_error);
+            }
+
+            return Ok(if relation.a_is_expected() { a_error } else { b_error });
         }
 
         match (a.kind(), b.kind()) {
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 54a62326ef7..c92a74b6241 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -1,3 +1,4 @@
+use crate::infer::DefineOpaqueTypes;
 use crate::traits::PredicateObligations;
 
 use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir};
@@ -110,7 +111,8 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
             }
             (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
             | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
-                if self.fields.define_opaque_types && def_id.is_local() =>
+                if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
+                    && def_id.is_local() =>
             {
                 self.fields.obligations.extend(
                     infcx
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 8a2b800af0e..fd16363a1db 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -359,10 +359,12 @@ impl<'tcx> InferCtxt<'tcx> {
     pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         let (def_id, substs) = match *ty.kind() {
             ty::Alias(_, ty::AliasTy { def_id, substs, .. })
-                if matches!(
-                    self.tcx.def_kind(def_id),
-                    DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
-                ) =>
+                if matches!(self.tcx.def_kind(def_id), DefKind::OpaqueTy) =>
+            {
+                (def_id, substs)
+            }
+            ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+                if self.tcx.is_impl_trait_in_trait(def_id) =>
             {
                 (def_id, substs)
             }
@@ -613,9 +615,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
 
         let report_path_match = |err: &mut Diagnostic, did1: DefId, did2: DefId| {
-            // Only external crates, if either is from a local
-            // module we could have false positives
-            if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
+            // Only report definitions from different crates. If both definitions
+            // are from a local module we could have false positives, e.g.
+            // let _ = [{struct Foo; Foo}, {struct Foo; Foo}];
+            if did1.krate != did2.krate {
                 let abs_path =
                     |def_id| AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]);
 
@@ -627,10 +630,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 };
                 if same_path().unwrap_or(false) {
                     let crate_name = self.tcx.crate_name(did1.krate);
-                    err.note(&format!(
-                        "perhaps two different versions of crate `{}` are being used?",
-                        crate_name
-                    ));
+                    let msg = if did1.is_local() || did2.is_local() {
+                        format!(
+                            "the crate `{crate_name}` is compiled multiple times, possibly with different configurations"
+                        )
+                    } else {
+                        format!(
+                            "perhaps two different versions of crate `{crate_name}` are being used?"
+                        )
+                    };
+                    err.note(msg);
                 }
             }
         };
@@ -1568,6 +1577,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
                         (false, Mismatch::Fixed("trait"))
                     }
+                    ValuePairs::Aliases(infer::ExpectedFound { expected, .. }) => {
+                        (false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id)))
+                    }
                     ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
                 };
                 let Some(vals) = self.values_str(values) else {
@@ -1754,8 +1766,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 )
                             }
                             (true, ty::Alias(ty::Projection, proj))
-                                if self.tcx.def_kind(proj.def_id)
-                                    == DefKind::ImplTraitPlaceholder =>
+                                if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
                             {
                                 let sm = self.tcx.sess.source_map();
                                 let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
@@ -2124,6 +2135,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         match values {
             infer::Regions(exp_found) => self.expected_found_str(exp_found),
             infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
+            infer::Aliases(exp_found) => self.expected_found_str(exp_found),
             infer::TraitRefs(exp_found) => {
                 let pretty_exp_found = ty::error::ExpectedFound {
                     expected: exp_found.expected.print_only_trait_path(),
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 7ffe1fd20b4..e720af73c39 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -306,9 +306,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             // Replace the explicit self type with `Self` for better suggestion rendering
             .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
             .substs;
-        let trait_item_substs =
-            ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id())
-                .rebase_onto(self.tcx, impl_def_id, trait_substs);
+        let trait_item_substs = ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id)
+            .rebase_onto(self.tcx, impl_def_id, trait_substs);
 
         let Ok(trait_predicates) = self
             .tcx
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index b33729d0be5..b38bbdfe7bb 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -1,7 +1,7 @@
 use super::TypeErrCtxt;
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{pluralize, Diagnostic, MultiSpan};
-use rustc_hir::{self as hir, def::DefKind};
+use rustc_hir as hir;
 use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::print::Printer;
@@ -75,7 +75,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         diag.note("an associated type was expected, but a different one was found");
                     }
                     (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
-                        if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
+                        if !tcx.is_impl_trait_in_trait(proj.def_id) =>
                     {
                         let p_def_id = tcx
                             .generics_of(body_owner_def_id)
@@ -222,7 +222,7 @@ impl<T> Trait<T> for X {
                             diag.span_label(p_span, "this type parameter");
                         }
                     }
-                    (ty::Alias(ty::Projection, proj_ty), _) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
+                    (ty::Alias(ty::Projection, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
                         self.expected_projection(
                             diag,
                             proj_ty,
@@ -231,7 +231,7 @@ impl<T> Trait<T> for X {
                             cause.code(),
                         );
                     }
-                    (_, ty::Alias(ty::Projection, proj_ty)) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
+                    (_, ty::Alias(ty::Projection, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
                         let msg = format!(
                             "consider constraining the associated type `{}` to `{}`",
                             values.found, values.expected,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 55dcfd05e0a..ec122dc039f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -356,7 +356,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
                 if !self.same_type_modulo_infer(*found_sig, *expected_sig)
                     || !sig.is_suggestable(self.tcx, true)
-                    || ty::util::is_intrinsic(self.tcx, *did)
+                    || self.tcx.is_intrinsic(*did)
                 {
                     return;
                 }
@@ -400,8 +400,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 if !self.same_type_modulo_infer(*found_sig, *expected_sig)
                     || !found_sig.is_suggestable(self.tcx, true)
                     || !expected_sig.is_suggestable(self.tcx, true)
-                    || ty::util::is_intrinsic(self.tcx, *did1)
-                    || ty::util::is_intrinsic(self.tcx, *did2)
+                    || self.tcx.is_intrinsic(*did1)
+                    || self.tcx.is_intrinsic(*did2)
                 {
                     return;
                 }
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 49df393d83b..5c12351226a 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -2,8 +2,8 @@
 
 use super::combine::{CombineFields, ObligationEmittingRelation};
 use super::lattice::{self, LatticeDir};
-use super::InferCtxt;
 use super::Subtype;
+use super::{DefineOpaqueTypes, InferCtxt};
 
 use crate::traits::{ObligationCause, PredicateObligations};
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
@@ -142,7 +142,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
         Ok(())
     }
 
-    fn define_opaque_types(&self) -> bool {
+    fn define_opaque_types(&self) -> DefineOpaqueTypes {
         self.fields.define_opaque_types
     }
 }
diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs
index f377ac1d19e..7f4c141b97a 100644
--- a/compiler/rustc_infer/src/infer/lattice.rs
+++ b/compiler/rustc_infer/src/infer/lattice.rs
@@ -19,7 +19,7 @@
 
 use super::combine::ObligationEmittingRelation;
 use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use super::InferCtxt;
+use super::{DefineOpaqueTypes, InferCtxt};
 
 use crate::traits::ObligationCause;
 use rustc_middle::ty::relate::RelateResult;
@@ -36,7 +36,7 @@ pub trait LatticeDir<'f, 'tcx>: ObligationEmittingRelation<'tcx> {
 
     fn cause(&self) -> &ObligationCause<'tcx>;
 
-    fn define_opaque_types(&self) -> bool;
+    fn define_opaque_types(&self) -> DefineOpaqueTypes;
 
     // Relates the type `v` to `a` and `b` such that `v` represents
     // the LUB/GLB of `a` and `b` as appropriate.
@@ -110,7 +110,7 @@ where
         ) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),
         (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
         | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
-            if this.define_opaque_types() && def_id.is_local() =>
+            if this.define_opaque_types() == DefineOpaqueTypes::Yes && def_id.is_local() =>
         {
             this.register_obligations(
                 infcx
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index c871ccb21f8..dbef42db8f1 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -2,8 +2,8 @@
 
 use super::combine::{CombineFields, ObligationEmittingRelation};
 use super::lattice::{self, LatticeDir};
-use super::InferCtxt;
 use super::Subtype;
+use super::{DefineOpaqueTypes, InferCtxt};
 
 use crate::traits::{ObligationCause, PredicateObligations};
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
@@ -142,7 +142,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
         Ok(())
     }
 
-    fn define_opaque_types(&self) -> bool {
+    fn define_opaque_types(&self) -> DefineOpaqueTypes {
         self.fields.define_opaque_types
     }
 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 4a834957959..aeb4ddb4212 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1,3 +1,4 @@
+pub use self::at::DefineOpaqueTypes;
 pub use self::freshen::TypeFreshener;
 pub use self::lexical_region_resolve::RegionResolutionError;
 pub use self::LateBoundRegionConversionTime::*;
@@ -187,6 +188,16 @@ impl<'tcx> InferCtxtInner<'tcx> {
     }
 
     #[inline]
+    fn try_type_variables_probe_ref(
+        &self,
+        vid: ty::TyVid,
+    ) -> Option<&type_variable::TypeVariableValue<'tcx>> {
+        // Uses a read-only view of the unification table, this way we don't
+        // need an undo log.
+        self.type_variable_storage.eq_relations_ref().try_probe_value(vid)
+    }
+
+    #[inline]
     fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> {
         self.type_variable_storage.with_log(&mut self.undo_log)
     }
@@ -338,6 +349,7 @@ pub struct InferCtxt<'tcx> {
 pub enum ValuePairs<'tcx> {
     Regions(ExpectedFound<ty::Region<'tcx>>),
     Terms(ExpectedFound<ty::Term<'tcx>>),
+    Aliases(ExpectedFound<ty::AliasTy<'tcx>>),
     TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
     PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
     Sigs(ExpectedFound<ty::FnSig<'tcx>>),
@@ -729,7 +741,7 @@ impl<'tcx> InferCtxt<'tcx> {
         &'a self,
         trace: TypeTrace<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        define_opaque_types: bool,
+        define_opaque_types: DefineOpaqueTypes,
     ) -> CombineFields<'a, 'tcx> {
         CombineFields {
             infcx: self,
@@ -864,7 +876,7 @@ impl<'tcx> InferCtxt<'tcx> {
         T: at::ToTrace<'tcx>,
     {
         let origin = &ObligationCause::dummy();
-        self.probe(|_| self.at(origin, param_env).sub(a, b).is_ok())
+        self.probe(|_| self.at(origin, param_env).sub(DefineOpaqueTypes::No, a, b).is_ok())
     }
 
     pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
@@ -872,7 +884,7 @@ impl<'tcx> InferCtxt<'tcx> {
         T: at::ToTrace<'tcx>,
     {
         let origin = &ObligationCause::dummy();
-        self.probe(|_| self.at(origin, param_env).eq(a, b).is_ok())
+        self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::No, a, b).is_ok())
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -967,7 +979,8 @@ impl<'tcx> InferCtxt<'tcx> {
             let ty::SubtypePredicate { a_is_expected, a, b } =
                 self.instantiate_binder_with_placeholders(predicate);
 
-            let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
+            let ok =
+                self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)?;
 
             Ok(ok.unit())
         }))
@@ -1643,6 +1656,28 @@ impl<'tcx> InferCtxt<'tcx> {
         tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
     }
 
+    /// The returned function is used in a fast path. If it returns `true` the variable is
+    /// unchanged, `false` indicates that the status is unknown.
+    #[inline]
+    pub fn is_ty_infer_var_definitely_unchanged<'a>(
+        &'a self,
+    ) -> (impl Fn(TyOrConstInferVar<'tcx>) -> bool + 'a) {
+        // This hoists the borrow/release out of the loop body.
+        let inner = self.inner.try_borrow();
+
+        return move |infer_var: TyOrConstInferVar<'tcx>| match (infer_var, &inner) {
+            (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => {
+                use self::type_variable::TypeVariableValue;
+
+                match inner.try_type_variables_probe_ref(ty_var) {
+                    Some(TypeVariableValue::Unknown { .. }) => true,
+                    _ => false,
+                }
+            }
+            _ => false,
+        };
+    }
+
     /// `ty_or_const_infer_var_changed` is equivalent to one of these two:
     ///   * `shallow_resolve(ty) != ty` (where `ty.kind = ty::Infer(_)`)
     ///   * `shallow_resolve(ct) != ct` (where `ct.kind = ty::ConstKind::Infer(_)`)
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index d5c824d4c41..3a0a0494a7e 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,11 +1,12 @@
+use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use super::{DefineOpaqueTypes, InferResult};
 use crate::errors::OpaqueHiddenTypeDiag;
 use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
 use crate::traits;
-use hir::def::DefKind;
 use hir::def_id::{DefId, LocalDefId};
 use hir::OpaqueTyOrigin;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::vec_map::VecMap;
 use rustc_hir as hir;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -16,18 +17,13 @@ use rustc_middle::ty::{
     TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
 use rustc_span::Span;
-
 use std::ops::ControlFlow;
 
-pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
-
 mod table;
 
+pub type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
 pub use table::{OpaqueTypeStorage, OpaqueTypeTable};
 
-use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use super::InferResult;
-
 /// Information about the opaque types whose values we
 /// are inferring in this function (these are the `impl Trait` that
 /// appear in the return type).
@@ -481,9 +477,7 @@ where
                 }
             }
 
-            ty::Alias(ty::Projection, proj)
-                if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder =>
-            {
+            ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => {
                 // Skip lifetime parameters that are not captures.
                 let variances = self.tcx.variances_of(proj.def_id);
 
@@ -547,8 +541,7 @@ impl<'tcx> InferCtxt<'tcx> {
         if let Some(prev) = prev {
             obligations = self
                 .at(&cause, param_env)
-                .define_opaque_types(true)
-                .eq_exp(a_is_expected, prev, hidden_ty)?
+                .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
                 .obligations;
         }
 
@@ -563,8 +556,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     // FIXME(RPITIT): Don't replace RPITITs with inference vars.
                     ty::Alias(ty::Projection, projection_ty)
                         if !projection_ty.has_escaping_bound_vars()
-                            && tcx.def_kind(projection_ty.def_id)
-                                != DefKind::ImplTraitPlaceholder =>
+                            && !tcx.is_impl_trait_in_trait(projection_ty.def_id) =>
                     {
                         self.infer_projection(
                             param_env,
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index 3e8c2052de8..230cadb1184 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -1,5 +1,5 @@
 use super::combine::{CombineFields, RelationDir};
-use super::{ObligationEmittingRelation, SubregionOrigin};
+use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin};
 
 use crate::traits::{Obligation, PredicateObligations};
 use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
@@ -138,7 +138,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
             }
             (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
             | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
-                if self.fields.define_opaque_types && def_id.is_local() =>
+                if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
+                    && def_id.is_local() =>
             {
                 self.fields.obligations.extend(
                     infcx
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 263c6a47dd2..f7ab05b2d49 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -190,6 +190,11 @@ impl<'tcx> TypeVariableStorage<'tcx> {
     ) -> TypeVariableTable<'a, 'tcx> {
         TypeVariableTable { storage: self, undo_log }
     }
+
+    #[inline]
+    pub(crate) fn eq_relations_ref(&self) -> &ut::UnificationTableStorage<TyVidEqKey<'tcx>> {
+        &self.eq_relations
+    }
 }
 
 impl<'tcx> TypeVariableTable<'_, 'tcx> {
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 77c67c14ecc..dd9b2e548c7 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -8,6 +8,8 @@ mod project;
 mod structural_impls;
 pub mod util;
 
+use std::cmp;
+
 use hir::def_id::LocalDefId;
 use rustc_hir as hir;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -139,6 +141,14 @@ impl<'tcx, O> Obligation<'tcx, O> {
         Self::with_depth(tcx, cause, 0, param_env, predicate)
     }
 
+    /// We often create nested obligations without setting the correct depth.
+    ///
+    /// To deal with this evaluate and fulfill explicitly update the depth
+    /// of nested obligations using this function.
+    pub fn set_depth_from_parent(&mut self, parent_depth: usize) {
+        self.recursion_depth = cmp::max(parent_depth + 1, self.recursion_depth);
+    }
+
     pub fn with_depth(
         tcx: TyCtxt<'tcx>,
         cause: ObligationCause<'tcx>,
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 18d84a7023a..014810dba9c 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -744,6 +744,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(emit_thin_lto, false);
     tracked!(export_executable_symbols, true);
     tracked!(fewer_names, Some(true));
+    tracked!(flatten_format_args, true);
     tracked!(force_unstable_if_unmarked, true);
     tracked!(fuel, Some(("abc".to_string(), 99)));
     tracked!(function_sections, Some(false));
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 68e62c9789a..c822237413c 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -508,3 +508,6 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass
     .specifically = this associated type bound is unsatisfied for `{$proj_ty}`
 
 lint_opaque_hidden_inferred_bound_sugg = add this bound
+
+lint_useless_anonymous_reexport = useless anonymous re-export
+    .note = only anonymous re-exports of traits are useful, this is {$article} `{$desc}`
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 5b2100b5da9..8af1a663ef5 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1306,7 +1306,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
         if fn_kind.asyncness() == IsAsync::Async
             && !cx.tcx.features().closure_track_caller
             // Now, check if the function has the `#[track_caller]` attribute
-            && let Some(attr) = cx.tcx.get_attr(def_id.to_def_id(), sym::track_caller)
+            && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
         {
             cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller {
                 label: span,
@@ -2748,10 +2748,7 @@ impl ClashingExternDeclarations {
                 // information, we could have codegen_fn_attrs also give span information back for
                 // where the attribute was defined. However, until this is found to be a
                 // bottleneck, this does just fine.
-                (
-                    overridden_link_name,
-                    tcx.get_attr(fi.owner_id.to_def_id(), sym::link_name).unwrap().span,
-                )
+                (overridden_link_name, tcx.get_attr(fi.owner_id, sym::link_name).unwrap().span)
             })
         {
             SymbolName::Link(overridden_link_name, overridden_link_name_span)
@@ -2781,8 +2778,7 @@ impl ClashingExternDeclarations {
 
             // Given a transparent newtype, reach through and grab the inner
             // type unless the newtype makes the type non-null.
-            let non_transparent_ty = |ty: Ty<'tcx>| -> Ty<'tcx> {
-                let mut ty = ty;
+            let non_transparent_ty = |mut ty: Ty<'tcx>| -> Ty<'tcx> {
                 loop {
                     if let ty::Adt(def, substs) = *ty.kind() {
                         let is_transparent = def.repr().transparent();
@@ -2792,14 +2788,14 @@ impl ClashingExternDeclarations {
                             ty, is_transparent, is_non_null
                         );
                         if is_transparent && !is_non_null {
-                            debug_assert!(def.variants().len() == 1);
+                            debug_assert_eq!(def.variants().len(), 1);
                             let v = &def.variant(VariantIdx::new(0));
-                            ty = transparent_newtype_field(tcx, v)
-                                .expect(
-                                    "single-variant transparent structure with zero-sized field",
-                                )
-                                .ty(tcx, substs);
-                            continue;
+                            // continue with `ty`'s non-ZST field,
+                            // otherwise `ty` is a ZST and we can return
+                            if let Some(field) = transparent_newtype_field(tcx, v) {
+                                ty = field.ty(tcx, substs);
+                                continue;
+                            }
                         }
                     }
                     debug!("non_transparent_ty -> {:?}", ty);
@@ -2813,10 +2809,8 @@ impl ClashingExternDeclarations {
             if !seen_types.insert((a, b)) {
                 // We've encountered a cycle. There's no point going any further -- the types are
                 // structurally the same.
-                return true;
-            }
-            let tcx = cx.tcx;
-            if a == b {
+                true
+            } else if a == b {
                 // All nominally-same types are structurally same, too.
                 true
             } else {
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index a3367ae4a9f..7b58bf03bbe 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -11,6 +11,7 @@ use rustc_hir as hir;
 use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
 use rustc_middle::ty::{self, List};
 use rustc_span::{sym, Span};
+use rustc_trait_selection::traits::ObligationCtxt;
 
 declare_lint! {
     /// The `for_loops_over_fallibles` lint checks for `for` loops over `Option` or `Result` values.
@@ -136,20 +137,22 @@ fn suggest_question_mark<'tcx>(
 
     let ty = substs.type_at(0);
     let infcx = cx.tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(&infcx);
+
     let body_def_id = cx.tcx.hir().body_owner_def_id(body_id);
     let cause = ObligationCause::new(
         span,
         body_def_id,
         rustc_infer::traits::ObligationCauseCode::MiscObligation,
     );
-    let errors = rustc_trait_selection::traits::fully_solve_bound(
-        &infcx,
+
+    ocx.register_bound(
         cause,
-        ty::ParamEnv::empty(),
+        cx.param_env,
         // Erase any region vids from the type, which may not be resolved
         infcx.tcx.erase_regions(ty),
         into_iterator_did,
     );
 
-    errors.is_empty()
+    ocx.select_all_or_error().is_empty()
 }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index a14dc20fca3..9c7feadaf87 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -386,7 +386,7 @@ impl LateLintPass<'_> for Diagnostics {
         for (hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
             if let Some(owner_did) = hir_id.as_owner() {
                 found_parent_with_attr = found_parent_with_attr
-                    || cx.tcx.has_attr(owner_did.to_def_id(), sym::rustc_lint_diagnostics);
+                    || cx.tcx.has_attr(owner_did, sym::rustc_lint_diagnostics);
             }
 
             debug!(?parent);
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index b3578540516..c2cc2fcdf55 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -74,6 +74,7 @@ mod opaque_hidden_inferred_bound;
 mod pass_by_value;
 mod passes;
 mod redundant_semicolon;
+mod reexports;
 mod traits;
 mod types;
 mod unused;
@@ -111,6 +112,7 @@ use noop_method_call::*;
 use opaque_hidden_inferred_bound::*;
 use pass_by_value::*;
 use redundant_semicolon::*;
+use reexports::*;
 use traits::*;
 use types::*;
 use unused::*;
@@ -242,6 +244,7 @@ late_lint_methods!(
             OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
             MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
             MapUnitFn: MapUnitFn,
+            UselessAnonymousReexport: UselessAnonymousReexport,
         ]
     ]
 );
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 20ab0af5856..46a025f41e0 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1390,7 +1390,7 @@ pub struct UnusedOp<'a> {
     pub op: &'a str,
     #[label]
     pub label: Span,
-    #[suggestion(style = "verbose", code = "let _ = ", applicability = "machine-applicable")]
+    #[suggestion(style = "verbose", code = "let _ = ", applicability = "maybe-incorrect")]
     pub suggestion: Span,
 }
 
@@ -1434,17 +1434,15 @@ pub struct UnusedDef<'a, 'b> {
 }
 
 #[derive(Subdiagnostic)]
-pub enum UnusedDefSuggestion {
-    #[suggestion(
-        lint_suggestion,
-        style = "verbose",
-        code = "let _ = ",
-        applicability = "machine-applicable"
-    )]
-    Default {
-        #[primary_span]
-        span: Span,
-    },
+#[suggestion(
+    lint_suggestion,
+    style = "verbose",
+    code = "let _ = ",
+    applicability = "maybe-incorrect"
+)]
+pub struct UnusedDefSuggestion {
+    #[primary_span]
+    pub span: Span,
 }
 
 // Needed because of def_path_str
@@ -1530,3 +1528,11 @@ pub struct UnusedAllocationDiag;
 #[derive(LintDiagnostic)]
 #[diag(lint_unused_allocation_mut)]
 pub struct UnusedAllocationMutDiag;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_useless_anonymous_reexport)]
+#[note]
+pub struct UselessAnonymousReexportDiag {
+    pub article: &'static str,
+    pub desc: &'static str,
+}
diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs
index 62e8b4fe9e4..7c692fee333 100644
--- a/compiler/rustc_lint/src/map_unit_fn.rs
+++ b/compiler/rustc_lint/src/map_unit_fn.rs
@@ -56,6 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn {
                         return;
                     }
                     let arg_ty = cx.typeck_results().expr_ty(&args[0]);
+                    let default_span = args[0].span;
                     if let ty::FnDef(id, _) = arg_ty.kind() {
                         let fn_ty = cx.tcx.fn_sig(id).skip_binder();
                         let ret_ty = fn_ty.output().skip_binder();
@@ -64,7 +65,10 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn {
                                 MAP_UNIT_FN,
                                 span,
                                 MappingToUnit {
-                                    function_label: cx.tcx.span_of_impl(*id).unwrap(),
+                                    function_label: cx
+                                        .tcx
+                                        .span_of_impl(*id)
+                                        .unwrap_or(default_span),
                                     argument_label: args[0].span,
                                     map_label: arg_ty.default_span(cx.tcx),
                                     suggestion: path.ident.span,
@@ -80,7 +84,10 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn {
                                 MAP_UNIT_FN,
                                 span,
                                 MappingToUnit {
-                                    function_label: cx.tcx.span_of_impl(*id).unwrap(),
+                                    function_label: cx
+                                        .tcx
+                                        .span_of_impl(*id)
+                                        .unwrap_or(default_span),
                                     argument_label: args[0].span,
                                     map_label: arg_ty.default_span(cx.tcx),
                                     suggestion: path.ident.span,
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 71e2e66bdeb..0f44dde5948 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -384,9 +384,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
         match &fk {
             FnKind::Method(ident, sig, ..) => match method_context(cx, id) {
                 MethodLateContext::PlainImpl => {
-                    if sig.header.abi != Abi::Rust
-                        && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle)
-                    {
+                    if sig.header.abi != Abi::Rust && cx.tcx.has_attr(id, sym::no_mangle) {
                         return;
                     }
                     self.check_snake_case(cx, "method", ident);
@@ -398,7 +396,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
             },
             FnKind::ItemFn(ident, _, header) => {
                 // Skip foreign-ABI #[no_mangle] functions (Issue #31924)
-                if header.abi != Abi::Rust && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) {
+                if header.abi != Abi::Rust && cx.tcx.has_attr(id, sym::no_mangle) {
                     return;
                 }
                 self.check_snake_case(cx, "function", ident);
diff --git a/compiler/rustc_lint/src/reexports.rs b/compiler/rustc_lint/src/reexports.rs
new file mode 100644
index 00000000000..8737a57ea02
--- /dev/null
+++ b/compiler/rustc_lint/src/reexports.rs
@@ -0,0 +1,82 @@
+use crate::lints::UselessAnonymousReexportDiag;
+use crate::{LateContext, LateLintPass, LintContext};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_hir::{Item, ItemKind, UseKind};
+use rustc_middle::ty::Visibility;
+use rustc_span::symbol::kw;
+use rustc_span::Span;
+
+declare_lint! {
+    /// The `useless_anonymous_reexport` lint checks if anonymous re-exports
+    /// are re-exports of traits.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(useless_anonymous_reexport)]
+    ///
+    /// mod sub {
+    ///     pub struct Bar;
+    /// }
+    ///
+    /// pub use self::sub::Bar as _;
+    /// # fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Anonymous re-exports are only useful if it's a re-export of a trait
+    /// in case you want to give access to it. If you re-export any other kind,
+    /// you won't be able to use it since its name won't be accessible.
+    pub USELESS_ANONYMOUS_REEXPORT,
+    Warn,
+    "useless anonymous re-export"
+}
+
+declare_lint_pass!(UselessAnonymousReexport => [USELESS_ANONYMOUS_REEXPORT]);
+
+fn emit_err(cx: &LateContext<'_>, span: Span, def_id: DefId) {
+    let article = cx.tcx.def_descr_article(def_id);
+    let desc = cx.tcx.def_descr(def_id);
+    cx.emit_spanned_lint(
+        USELESS_ANONYMOUS_REEXPORT,
+        span,
+        UselessAnonymousReexportDiag { article, desc },
+    );
+}
+
+impl<'tcx> LateLintPass<'tcx> for UselessAnonymousReexport {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if let ItemKind::Use(path, kind) = item.kind &&
+            !matches!(kind, UseKind::Glob) &&
+            item.ident.name == kw::Underscore &&
+            // We only want re-exports. If it's just a `use X;`, then we ignore it.
+            match cx.tcx.local_visibility(item.owner_id.def_id) {
+                Visibility::Public => true,
+                Visibility::Restricted(level) => {
+                    level != cx.tcx.parent_module_from_def_id(item.owner_id.def_id)
+                }
+            }
+        {
+            for def_id in path.res.iter().filter_map(|r| r.opt_def_id()) {
+                match cx.tcx.def_kind(def_id) {
+                    DefKind::Trait | DefKind::TraitAlias => {}
+                    DefKind::TyAlias => {
+                        let ty = cx.tcx.type_of(def_id);
+                        if !ty.0.is_trait() {
+                            emit_err(cx, item.span, def_id);
+                            break;
+                        }
+                    }
+                    _ => {
+                        emit_err(cx, item.span, def_id);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 2fab82d55cd..faca61fc29b 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
         let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span);
         let type_lint_emitted_or_suppressed = match must_use_result {
             Some(path) => {
-                emit_must_use_untranslated(cx, &path, "", "", 1);
+                emit_must_use_untranslated(cx, &path, "", "", 1, false);
                 true
             }
             None => false,
@@ -358,6 +358,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                         descr_pre_path,
                         descr_post_path,
                         1,
+                        false,
                     )
                 })
                 .is_some()
@@ -370,6 +371,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
             descr_pre: &str,
             descr_post: &str,
             plural_len: usize,
+            is_inner: bool,
         ) {
             let plural_suffix = pluralize!(plural_len);
 
@@ -377,20 +379,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                 MustUsePath::Suppressed => {}
                 MustUsePath::Boxed(path) => {
                     let descr_pre = &format!("{}boxed ", descr_pre);
-                    emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len);
+                    emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true);
                 }
                 MustUsePath::Opaque(path) => {
                     let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix);
-                    emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len);
+                    emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true);
                 }
                 MustUsePath::TraitObject(path) => {
                     let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post);
-                    emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len);
+                    emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true);
                 }
                 MustUsePath::TupleElement(elems) => {
                     for (index, path) in elems {
                         let descr_post = &format!(" in tuple element {}", index);
-                        emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len);
+                        emit_must_use_untranslated(
+                            cx, path, descr_pre, descr_post, plural_len, true,
+                        );
                     }
                 }
                 MustUsePath::Array(path, len) => {
@@ -401,6 +405,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                         descr_pre,
                         descr_post,
                         plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)),
+                        true,
                     );
                 }
                 MustUsePath::Closure(span) => {
@@ -418,19 +423,6 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                     );
                 }
                 MustUsePath::Def(span, def_id, reason) => {
-                    let suggestion = if matches!(
-                        cx.tcx.get_diagnostic_name(*def_id),
-                        Some(sym::add)
-                            | Some(sym::sub)
-                            | Some(sym::mul)
-                            | Some(sym::div)
-                            | Some(sym::rem)
-                            | Some(sym::neg),
-                    ) {
-                        Some(UnusedDefSuggestion::Default { span: span.shrink_to_lo() })
-                    } else {
-                        None
-                    };
                     cx.emit_spanned_lint(
                         UNUSED_MUST_USE,
                         *span,
@@ -440,7 +432,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                             cx,
                             def_id: *def_id,
                             note: *reason,
-                            suggestion,
+                            suggestion: (!is_inner)
+                                .then_some(UnusedDefSuggestion { span: span.shrink_to_lo() }),
                         },
                     );
                 }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 46ec1a2dca1..91966e75b5f 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1026,12 +1026,13 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,compile_fail
-    /// #![feature(const_ptr_read)]
+    /// #![feature(const_mut_refs)]
     /// const FOO: () = unsafe {
     ///     let x = &[0_u8; 4];
     ///     let y = x.as_ptr().cast::<u32>();
-    ///     y.read(); // the address of a `u8` array is unknown and thus we don't know if
-    ///     // it is aligned enough for reading a `u32`.
+    ///     let mut z = 123;
+    ///     y.copy_to_nonoverlapping(&mut z, 1); // the address of a `u8` array is unknown
+    ///     // and thus we don't know if it is aligned enough for copying a `u32`.
     /// };
     /// ```
     ///
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index d6f68b2e140..b855c8e4332 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -46,7 +46,7 @@ pub fn find_native_static_library(
 }
 
 fn find_bundled_library(
-    name: Option<Symbol>,
+    name: Symbol,
     verbatim: Option<bool>,
     kind: NativeLibKind,
     has_cfg: bool,
@@ -58,7 +58,7 @@ fn find_bundled_library(
     {
         let verbatim = verbatim.unwrap_or(false);
         let search_paths = &sess.target_filesearch(PathKind::Native).search_path_dirs();
-        return find_native_static_library(name.unwrap().as_str(), verbatim, search_paths, sess)
+        return find_native_static_library(name.as_str(), verbatim, search_paths, sess)
             .file_name()
             .and_then(|s| s.to_str())
             .map(Symbol::intern);
@@ -336,10 +336,16 @@ impl<'tcx> Collector<'tcx> {
                 if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
                     sess.emit_err(errors::IncompatibleWasmLink { span });
                 }
-            } else if name.is_none() {
-                sess.emit_err(errors::LinkRequiresName { span: m.span });
             }
 
+            if wasm_import_module.is_some() {
+                (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
+            }
+            let Some((name, name_span)) = name else {
+                sess.emit_err(errors::LinkRequiresName { span: m.span });
+                continue;
+            };
+
             // Do this outside of the loop so that `import_name_type` can be specified before `kind`.
             if let Some((_, span)) = import_name_type {
                 if kind != Some(NativeLibKind::RawDylib) {
@@ -349,8 +355,8 @@ impl<'tcx> Collector<'tcx> {
 
             let dll_imports = match kind {
                 Some(NativeLibKind::RawDylib) => {
-                    if let Some((name, span)) = name && name.as_str().contains('\0') {
-                        sess.emit_err(errors::RawDylibNoNul { span });
+                    if name.as_str().contains('\0') {
+                        sess.emit_err(errors::RawDylibNoNul { span: name_span });
                     }
                     foreign_mod_items
                         .iter()
@@ -389,7 +395,6 @@ impl<'tcx> Collector<'tcx> {
                 }
             };
 
-            let name = name.map(|(name, _)| name);
             let kind = kind.unwrap_or(NativeLibKind::Unspecified);
             let filename = find_bundled_library(name, verbatim, kind, cfg.is_some(), sess);
             self.libs.push(NativeLib {
@@ -398,7 +403,6 @@ impl<'tcx> Collector<'tcx> {
                 kind,
                 cfg,
                 foreign_module: Some(it.owner_id.to_def_id()),
-                wasm_import_module: wasm_import_module.map(|(name, _)| name),
                 verbatim,
                 dll_imports,
             });
@@ -415,11 +419,7 @@ impl<'tcx> Collector<'tcx> {
                 self.tcx.sess.emit_err(errors::LibFrameworkApple);
             }
             if let Some(ref new_name) = lib.new_name {
-                let any_duplicate = self
-                    .libs
-                    .iter()
-                    .filter_map(|lib| lib.name.as_ref())
-                    .any(|n| n.as_str() == lib.name);
+                let any_duplicate = self.libs.iter().any(|n| n.name.as_str() == lib.name);
                 if new_name.is_empty() {
                     self.tcx.sess.emit_err(errors::EmptyRenamingTarget { lib_name: &lib.name });
                 } else if !any_duplicate {
@@ -444,33 +444,28 @@ impl<'tcx> Collector<'tcx> {
             let mut existing = self
                 .libs
                 .drain_filter(|lib| {
-                    if let Some(lib_name) = lib.name {
-                        if lib_name.as_str() == passed_lib.name {
-                            // FIXME: This whole logic is questionable, whether modifiers are
-                            // involved or not, library reordering and kind overriding without
-                            // explicit `:rename` in particular.
-                            if lib.has_modifiers() || passed_lib.has_modifiers() {
-                                match lib.foreign_module {
-                                    Some(def_id) => {
-                                        self.tcx.sess.emit_err(errors::NoLinkModOverride {
-                                            span: Some(self.tcx.def_span(def_id)),
-                                        })
-                                    }
-                                    None => self
-                                        .tcx
-                                        .sess
-                                        .emit_err(errors::NoLinkModOverride { span: None }),
-                                };
-                            }
-                            if passed_lib.kind != NativeLibKind::Unspecified {
-                                lib.kind = passed_lib.kind;
-                            }
-                            if let Some(new_name) = &passed_lib.new_name {
-                                lib.name = Some(Symbol::intern(new_name));
-                            }
-                            lib.verbatim = passed_lib.verbatim;
-                            return true;
+                    if lib.name.as_str() == passed_lib.name {
+                        // FIXME: This whole logic is questionable, whether modifiers are
+                        // involved or not, library reordering and kind overriding without
+                        // explicit `:rename` in particular.
+                        if lib.has_modifiers() || passed_lib.has_modifiers() {
+                            match lib.foreign_module {
+                                Some(def_id) => self.tcx.sess.emit_err(errors::NoLinkModOverride {
+                                    span: Some(self.tcx.def_span(def_id)),
+                                }),
+                                None => {
+                                    self.tcx.sess.emit_err(errors::NoLinkModOverride { span: None })
+                                }
+                            };
+                        }
+                        if passed_lib.kind != NativeLibKind::Unspecified {
+                            lib.kind = passed_lib.kind;
+                        }
+                        if let Some(new_name) = &passed_lib.new_name {
+                            lib.name = Symbol::intern(new_name);
                         }
+                        lib.verbatim = passed_lib.verbatim;
+                        return true;
                     }
                     false
                 })
@@ -478,7 +473,7 @@ impl<'tcx> Collector<'tcx> {
             if existing.is_empty() {
                 // Add if not found
                 let new_name: Option<&str> = passed_lib.new_name.as_deref();
-                let name = Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name)));
+                let name = Symbol::intern(new_name.unwrap_or(&passed_lib.name));
                 let sess = self.tcx.sess;
                 let filename =
                     find_bundled_library(name, passed_lib.verbatim, passed_lib.kind, false, sess);
@@ -488,7 +483,6 @@ impl<'tcx> Collector<'tcx> {
                     kind: passed_lib.kind,
                     cfg: None,
                     foreign_module: None,
-                    wasm_import_module: None,
                     verbatim: passed_lib.verbatim,
                     dll_imports: Vec::new(),
                 });
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index ca26e1497aa..0070e46ffdf 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1087,6 +1087,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
         };
         let container = self.root.tables.assoc_container.get(self, id).unwrap();
+        let opt_rpitit_info =
+            self.root.tables.opt_rpitit_info.get(self, id).map(|d| d.decode(self));
 
         ty::AssocItem {
             name,
@@ -1095,8 +1097,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             trait_item_def_id: self.get_trait_item_def_id(id),
             container,
             fn_has_self_parameter: has_self,
-            // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): We need to encode this
-            opt_rpitit_info: None,
+            opt_rpitit_info,
         }
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 6c5e8863010..9661e815623 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -13,6 +13,7 @@ use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
 use rustc_middle::middle::stability::DeprecationEntry;
+use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::{self, TyCtxt};
@@ -226,7 +227,7 @@ provide! { tcx, def_id, other, cdata,
     lookup_default_body_stability => { table }
     lookup_deprecation_entry => { table }
     params_in_repr => { table }
-    unused_generic_params => { table }
+    unused_generic_params => { cdata.root.tables.unused_generic_params.get(cdata, def_id.index) }
     opt_def_kind => { table_direct }
     impl_parent => { table }
     impl_polarity => { table_direct }
@@ -254,7 +255,7 @@ provide! { tcx, def_id, other, cdata,
             .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys")))
      }
 
-    associated_items_for_impl_trait_in_trait => { table_defaulted_array }
+    associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array }
 
     visibility => { cdata.get_visibility(def_id.index) }
     adt_def => { cdata.get_adt_def(def_id.index, tcx) }
@@ -367,10 +368,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
     *providers = Providers {
         allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(),
         alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(),
-        is_private_dep: |_tcx, cnum| {
-            assert_eq!(cnum, LOCAL_CRATE);
-            false
-        },
+        is_private_dep: |_tcx, LocalCrate| false,
         native_library: |tcx, id| {
             tcx.native_libraries(id.krate)
                 .iter()
@@ -386,12 +384,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                         .contains(&id)
                 })
         },
-        native_libraries: |tcx, cnum| {
-            assert_eq!(cnum, LOCAL_CRATE);
-            native_libs::collect(tcx)
-        },
-        foreign_modules: |tcx, cnum| {
-            assert_eq!(cnum, LOCAL_CRATE);
+        native_libraries: |tcx, LocalCrate| native_libs::collect(tcx),
+        foreign_modules: |tcx, LocalCrate| {
             foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect()
         },
 
@@ -489,14 +483,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
         },
 
         dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)),
-        has_global_allocator: |tcx, cnum| {
-            assert_eq!(cnum, LOCAL_CRATE);
-            CStore::from_tcx(tcx).has_global_allocator()
-        },
-        has_alloc_error_handler: |tcx, cnum| {
-            assert_eq!(cnum, LOCAL_CRATE);
-            CStore::from_tcx(tcx).has_alloc_error_handler()
-        },
+        has_global_allocator: |tcx, LocalCrate| CStore::from_tcx(tcx).has_global_allocator(),
+        has_alloc_error_handler: |tcx, LocalCrate| CStore::from_tcx(tcx).has_alloc_error_handler(),
         postorder_cnums: |tcx, ()| {
             tcx.arena
                 .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index bbab8a62a2b..ef3eda584e1 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -24,6 +24,7 @@ use rustc_middle::middle::exported_symbols::{
     metadata_symbol_name, ExportedSymbol, SymbolExportInfo,
 };
 use rustc_middle::mir::interpret;
+use rustc_middle::query::LocalCrate;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
 use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections};
@@ -609,10 +610,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         _ = stat!("mir", || self.encode_mir());
 
-        _ = stat!("items", || {
-            self.encode_def_ids();
-            self.encode_info_for_items();
-        });
+        _ = stat!("def-ids", || self.encode_def_ids());
+
+        _ = stat!("items", || self.encode_info_for_items());
 
         let interpret_alloc_index = stat!("interpret-alloc-index", || {
             let mut interpret_alloc_index = Vec::new();
@@ -1028,7 +1028,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
         | DefKind::InlineConst => true,
 
         DefKind::ImplTraitPlaceholder => {
-            let parent_def_id = tcx.impl_trait_in_trait_parent(def_id.to_def_id());
+            let parent_def_id = tcx.impl_trait_in_trait_parent_fn(def_id.to_def_id());
             let assoc_item = tcx.associated_item(parent_def_id);
             match assoc_item.container {
                 // Always encode an RPIT in an impl fn, since it always has a body
@@ -1198,8 +1198,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record!(self.tables.trait_impl_trait_tys[def_id] <- table);
             }
             if should_encode_fn_impl_trait_in_trait(tcx, def_id) {
-                let table = tcx.associated_items_for_impl_trait_in_trait(def_id);
-                record_defaulted_array!(self.tables.associated_items_for_impl_trait_in_trait[def_id] <- table);
+                let table = tcx.associated_types_for_impl_traits_in_associated_fn(def_id);
+                record_defaulted_array!(self.tables.associated_types_for_impl_traits_in_associated_fn[def_id] <- table);
             }
         }
 
@@ -1350,19 +1350,24 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         if trait_item.kind == ty::AssocKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
         }
+        if let Some(rpitit_info) = trait_item.opt_rpitit_info {
+            let rpitit_info = self.lazy(rpitit_info);
+            self.tables.opt_rpitit_info.set_some(def_id.index, rpitit_info);
+        }
     }
 
     fn encode_info_for_impl_item(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_info_for_impl_item({:?})", def_id);
         let tcx = self.tcx;
 
-        let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
-        self.tables.impl_defaultness.set_some(def_id.index, ast_item.defaultness);
+        let defaultness = self.tcx.impl_defaultness(def_id.expect_local());
+        self.tables.impl_defaultness.set_some(def_id.index, defaultness);
         let impl_item = self.tcx.associated_item(def_id);
         self.tables.assoc_container.set_some(def_id.index, impl_item.container);
 
         match impl_item.kind {
             ty::AssocKind::Fn => {
+                let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
                 let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
                 self.tables.asyncness.set_some(def_id.index, sig.header.asyncness);
                 record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
@@ -1383,6 +1388,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
             self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
         }
+        if let Some(rpitit_info) = impl_item.opt_rpitit_info {
+            let rpitit_info = self.lazy(rpitit_info);
+            self.tables.opt_rpitit_info.set_some(def_id.index, rpitit_info);
+        }
     }
 
     fn encode_mir(&mut self) {
@@ -1431,9 +1440,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             let instance =
                 ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id()));
             let unused = tcx.unused_generic_params(instance);
-            if !unused.all_used() {
-                record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
-            }
+            self.tables.unused_generic_params.set(def_id.local_def_index, unused);
         }
 
         // Encode all the deduced parameter attributes for everything that has MIR, even for items
@@ -2225,18 +2232,16 @@ pub fn provide(providers: &mut Providers) {
         doc_link_resolutions: |tcx, def_id| {
             tcx.resolutions(())
                 .doc_link_resolutions
-                .get(&def_id.expect_local())
+                .get(&def_id)
                 .expect("no resolutions for a doc link")
         },
         doc_link_traits_in_scope: |tcx, def_id| {
             tcx.resolutions(())
                 .doc_link_traits_in_scope
-                .get(&def_id.expect_local())
+                .get(&def_id)
                 .expect("no traits in scope for a doc link")
         },
-        traits_in_crate: |tcx, cnum| {
-            assert_eq!(cnum, LOCAL_CRATE);
-
+        traits_in_crate: |tcx, LocalCrate| {
             let mut traits = Vec::new();
             for id in tcx.hir().items() {
                 if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) {
@@ -2248,9 +2253,7 @@ pub fn provide(providers: &mut Providers) {
             traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id));
             tcx.arena.alloc_slice(&traits)
         },
-        trait_impls_in_crate: |tcx, cnum| {
-            assert_eq!(cnum, LOCAL_CRATE);
-
+        trait_impls_in_crate: |tcx, LocalCrate| {
             let mut trait_impls = Vec::new();
             for id in tcx.hir().items() {
                 if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. })
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 1d2541a6788..6dc6041b284 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -354,7 +354,9 @@ define_tables! {
     explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
     inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
-    associated_items_for_impl_trait_in_trait: Table<DefIndex, LazyArray<DefId>>,
+    associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
+    opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>,
+    unused_generic_params: Table<DefIndex, UnusedGenericParams>,
 
 - optional:
     attributes: Table<DefIndex, LazyArray<ast::Attribute>>,
@@ -397,7 +399,6 @@ define_tables! {
     trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
     trait_item_def_id: Table<DefIndex, RawDefId>,
     expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
-    unused_generic_params: Table<DefIndex, LazyValue<UnusedGenericParams>>,
     params_in_repr: Table<DefIndex, LazyValue<BitSet<u32>>>,
     repr_options: Table<DefIndex, LazyValue<ReprOptions>>,
     // `def_keys` and `def_path_hashes` represent a lazy version of a
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index b89d48ec15a..364fa74ab7b 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -3,7 +3,7 @@ use crate::rmeta::*;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_hir::def::{CtorKind, CtorOf};
 use rustc_index::vec::Idx;
-use rustc_middle::ty::ParameterizedOverTcx;
+use rustc_middle::ty::{ParameterizedOverTcx, UnusedGenericParams};
 use rustc_serialize::opaque::FileEncoder;
 use rustc_serialize::Encoder as _;
 use rustc_span::hygiene::MacroKind;
@@ -50,6 +50,16 @@ impl IsDefault for DefPathHash {
     }
 }
 
+impl IsDefault for UnusedGenericParams {
+    fn is_default(&self) -> bool {
+        // UnusedGenericParams encodes the *un*usedness as a bitset.
+        // This means that 0 corresponds to all bits used, which is indeed the default.
+        let is_default = self.bits() == 0;
+        debug_assert_eq!(is_default, self.all_used());
+        is_default
+    }
+}
+
 /// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
 /// Used mainly for Lazy positions and lengths.
 /// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
@@ -271,6 +281,21 @@ impl FixedSizeEncoding for bool {
     }
 }
 
+impl FixedSizeEncoding for UnusedGenericParams {
+    type ByteArray = [u8; 4];
+
+    #[inline]
+    fn from_bytes(b: &[u8; 4]) -> Self {
+        let x: u32 = u32::from_bytes(b);
+        UnusedGenericParams::from_bits(x)
+    }
+
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 4]) {
+        self.bits().write_to_bytes(b);
+    }
+}
+
 // NOTE(eddyb) there could be an impl for `usize`, which would enable a more
 // generic `LazyValue<T>` impl, but in the general case we might not need / want
 // to fit every `usize` in `u32`.
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 746cf488589..b2bae47054c 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,4 +1,5 @@
 use crate::hir::{ModuleItems, Owner};
+use crate::query::LocalCrate;
 use crate::ty::TyCtxt;
 use rustc_ast as ast;
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -6,7 +7,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::*;
@@ -316,7 +317,7 @@ impl<'hir> Map<'hir> {
     /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
     #[inline]
     pub fn find_by_def_id(self, id: LocalDefId) -> Option<Node<'hir>> {
-        self.find(self.local_def_id_to_hir_id(id))
+        self.find(self.tcx.opt_local_def_id_to_hir_id(id)?)
     }
 
     /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
@@ -333,7 +334,7 @@ impl<'hir> Map<'hir> {
     }
 
     pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> {
-        id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
+        id.as_local().and_then(|id| self.find(self.tcx.opt_local_def_id_to_hir_id(id)?))
     }
 
     pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
@@ -1131,8 +1132,7 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> {
     }
 }
 
-pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
-    debug_assert_eq!(crate_num, LOCAL_CRATE);
+pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
     let krate = tcx.hir_crate(());
     let hir_body_hash = krate.opt_hir_hash.expect("HIR hash missing while computing crate hash");
 
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 403b2b65088..0d8a8c9cdfd 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -147,18 +147,18 @@ pub fn provide(providers: &mut Providers) {
         tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
     };
     providers.def_span = |tcx, def_id| {
-        let def_id = def_id.expect_local();
+        let def_id = def_id;
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
         tcx.hir().opt_span(hir_id).unwrap_or(DUMMY_SP)
     };
     providers.def_ident_span = |tcx, def_id| {
-        let def_id = def_id.expect_local();
+        let def_id = def_id;
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
         tcx.hir().opt_ident_span(hir_id)
     };
     providers.fn_arg_names = |tcx, id| {
         let hir = tcx.hir();
-        let def_id = id.expect_local();
+        let def_id = id;
         let hir_id = hir.local_def_id_to_hir_id(def_id);
         if let Some(body_id) = hir.maybe_body_owned_by(def_id) {
             tcx.arena.alloc_from_iter(hir.body_param_names(body_id))
@@ -176,12 +176,10 @@ pub fn provide(providers: &mut Providers) {
             span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id);
         }
     };
-    providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local());
+    providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id);
     providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls;
-    providers.expn_that_defined = |tcx, id| {
-        let id = id.expect_local();
-        tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root())
-    };
+    providers.expn_that_defined =
+        |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root());
     providers.in_scope_traits_map = |tcx, id| {
         tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map)
     };
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index b34651c3ea7..638c082cc84 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -401,8 +401,6 @@ impl<'tcx> Body<'tcx> {
             LocalKind::ReturnPointer
         } else if index < self.arg_count + 1 {
             LocalKind::Arg
-        } else if self.local_decls[local].is_user_variable() {
-            LocalKind::Var
         } else {
             LocalKind::Temp
         }
@@ -572,6 +570,13 @@ impl<T> ClearCrossCrate<T> {
         }
     }
 
+    pub fn as_mut(&mut self) -> ClearCrossCrate<&mut T> {
+        match self {
+            ClearCrossCrate::Clear => ClearCrossCrate::Clear,
+            ClearCrossCrate::Set(v) => ClearCrossCrate::Set(v),
+        }
+    }
+
     pub fn assert_crate_local(self) -> T {
         match self {
             ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"),
@@ -661,9 +666,7 @@ impl Atom for Local {
 /// Classifies locals into categories. See `Body::local_kind`.
 #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
 pub enum LocalKind {
-    /// User-declared variable binding.
-    Var,
-    /// Compiler-introduced temporary.
+    /// User-declared variable binding or compiler-introduced temporary.
     Temp,
     /// Function argument.
     Arg,
@@ -760,7 +763,7 @@ pub struct LocalDecl<'tcx> {
     pub mutability: Mutability,
 
     // FIXME(matthewjasper) Don't store in this in `Body`
-    pub local_info: Option<Box<LocalInfo<'tcx>>>,
+    pub local_info: ClearCrossCrate<Box<LocalInfo<'tcx>>>,
 
     /// `true` if this is an internal local.
     ///
@@ -778,13 +781,6 @@ pub struct LocalDecl<'tcx> {
     /// generator.
     pub internal: bool,
 
-    /// If this local is a temporary and `is_block_tail` is `Some`,
-    /// then it is a temporary created for evaluation of some
-    /// subexpression of some block's tail expression (with no
-    /// intervening statement context).
-    // FIXME(matthewjasper) Don't store in this in `Body`
-    pub is_block_tail: Option<BlockTailInfo>,
-
     /// The type of this local.
     pub ty: Ty<'tcx>,
 
@@ -890,7 +886,7 @@ pub enum LocalInfo<'tcx> {
     /// The `BindingForm` is solely used for local diagnostics when generating
     /// warnings/errors when compiling the current crate, and therefore it need
     /// not be visible across crates.
-    User(ClearCrossCrate<BindingForm<'tcx>>),
+    User(BindingForm<'tcx>),
     /// A temporary created that references the static with the given `DefId`.
     StaticRef { def_id: DefId, is_thread_local: bool },
     /// A temporary created that references the const with the given `DefId`
@@ -898,13 +894,23 @@ pub enum LocalInfo<'tcx> {
     /// A temporary created during the creation of an aggregate
     /// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`)
     AggregateTemp,
+    /// A temporary created for evaluation of some subexpression of some block's tail expression
+    /// (with no intervening statement context).
+    // FIXME(matthewjasper) Don't store in this in `Body`
+    BlockTailTemp(BlockTailInfo),
     /// A temporary created during the pass `Derefer` to avoid it's retagging
     DerefTemp,
     /// A temporary created for borrow checking.
     FakeBorrow,
+    /// A local without anything interesting about it.
+    Boring,
 }
 
 impl<'tcx> LocalDecl<'tcx> {
+    pub fn local_info(&self) -> &LocalInfo<'tcx> {
+        &**self.local_info.as_ref().assert_crate_local()
+    }
+
     /// Returns `true` only if local is a binding that can itself be
     /// made mutable via the addition of the `mut` keyword, namely
     /// something like the occurrences of `x` in:
@@ -913,15 +919,15 @@ impl<'tcx> LocalDecl<'tcx> {
     /// - or `match ... { C(x) => ... }`
     pub fn can_be_made_mutable(&self) -> bool {
         matches!(
-            self.local_info,
-            Some(box LocalInfo::User(ClearCrossCrate::Set(
+            self.local_info(),
+            LocalInfo::User(
                 BindingForm::Var(VarBindingForm {
                     binding_mode: ty::BindingMode::BindByValue(_),
                     opt_ty_info: _,
                     opt_match_place: _,
                     pat_span: _,
                 }) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
-            )))
+            )
         )
     }
 
@@ -930,15 +936,15 @@ impl<'tcx> LocalDecl<'tcx> {
     /// mutable bindings, but the inverse does not necessarily hold).
     pub fn is_nonref_binding(&self) -> bool {
         matches!(
-            self.local_info,
-            Some(box LocalInfo::User(ClearCrossCrate::Set(
+            self.local_info(),
+            LocalInfo::User(
                 BindingForm::Var(VarBindingForm {
                     binding_mode: ty::BindingMode::BindByValue(_),
                     opt_ty_info: _,
                     opt_match_place: _,
                     pat_span: _,
                 }) | BindingForm::ImplicitSelf(_),
-            )))
+            )
         )
     }
 
@@ -946,38 +952,35 @@ impl<'tcx> LocalDecl<'tcx> {
     /// parameter declared by the user.
     #[inline]
     pub fn is_user_variable(&self) -> bool {
-        matches!(self.local_info, Some(box LocalInfo::User(_)))
+        matches!(self.local_info(), LocalInfo::User(_))
     }
 
     /// Returns `true` if this is a reference to a variable bound in a `match`
     /// expression that is used to access said variable for the guard of the
     /// match arm.
     pub fn is_ref_for_guard(&self) -> bool {
-        matches!(
-            self.local_info,
-            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)))
-        )
+        matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard))
     }
 
     /// Returns `Some` if this is a reference to a static item that is used to
     /// access that static.
     pub fn is_ref_to_static(&self) -> bool {
-        matches!(self.local_info, Some(box LocalInfo::StaticRef { .. }))
+        matches!(self.local_info(), LocalInfo::StaticRef { .. })
     }
 
     /// Returns `Some` if this is a reference to a thread-local static item that is used to
     /// access that static.
     pub fn is_ref_to_thread_local(&self) -> bool {
-        match self.local_info {
-            Some(box LocalInfo::StaticRef { is_thread_local, .. }) => is_thread_local,
+        match self.local_info() {
+            LocalInfo::StaticRef { is_thread_local, .. } => *is_thread_local,
             _ => false,
         }
     }
 
     /// Returns `true` if this is a DerefTemp
     pub fn is_deref_temp(&self) -> bool {
-        match self.local_info {
-            Some(box LocalInfo::DerefTemp) => return true,
+        match self.local_info() {
+            LocalInfo::DerefTemp => return true,
             _ => (),
         }
         return false;
@@ -1001,9 +1004,8 @@ impl<'tcx> LocalDecl<'tcx> {
     pub fn with_source_info(ty: Ty<'tcx>, source_info: SourceInfo) -> Self {
         LocalDecl {
             mutability: Mutability::Mut,
-            local_info: None,
+            local_info: ClearCrossCrate::Set(Box::new(LocalInfo::Boring)),
             internal: false,
-            is_block_tail: None,
             ty,
             user_ty: None,
             source_info,
@@ -1023,14 +1025,6 @@ impl<'tcx> LocalDecl<'tcx> {
         self.mutability = Mutability::Not;
         self
     }
-
-    /// Converts `self` into same `LocalDecl` except tagged as internal temporary.
-    #[inline]
-    pub fn block_tail(mut self, info: BlockTailInfo) -> Self {
-        assert!(self.is_block_tail.is_none());
-        self.is_block_tail = Some(info);
-        self
-    }
 }
 
 #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
@@ -1274,6 +1268,13 @@ impl<'tcx> BasicBlockData<'tcx> {
 }
 
 impl<O> AssertKind<O> {
+    /// Returns true if this an overflow checking assertion controlled by -C overflow-checks.
+    pub fn is_optional_overflow_check(&self) -> bool {
+        use AssertKind::*;
+        use BinOp::*;
+        matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..))
+    }
+
     /// Getting a description does not require `O` to be printable, and does not
     /// require allocation.
     /// The caller is expected to handle `BoundsCheck` separately.
@@ -1998,16 +1999,6 @@ impl BorrowKind {
     }
 }
 
-impl BinOp {
-    /// The checkable operators are those whose overflow checking behavior is controlled by
-    /// -Coverflow-checks option. The remaining operators have either no overflow conditions (e.g.,
-    /// BitAnd, BitOr, BitXor) or are always checked for overflow (e.g., Div, Rem).
-    pub fn is_checkable(self) -> bool {
-        use self::BinOp::*;
-        matches!(self, Add | Sub | Mul | Shl | Shr)
-    }
-}
-
 impl<'tcx> Debug for Rvalue<'tcx> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         use self::Rvalue::*;
@@ -2534,7 +2525,7 @@ impl<'tcx> ConstantKind<'tcx> {
         let parent_substs = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id)
             && let Some(parent_did) = parent_hir_id.as_owner()
         {
-            InternalSubsts::identity_for_item(tcx, parent_did.to_def_id())
+            InternalSubsts::identity_for_item(tcx, parent_did)
         } else {
             List::empty()
         };
@@ -2563,7 +2554,7 @@ impl<'tcx> ConstantKind<'tcx> {
                 Self::Unevaluated(
                     UnevaluatedConst {
                         def: def.to_global(),
-                        substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
+                        substs: InternalSubsts::identity_for_item(tcx, def.did),
                         promoted: None,
                     },
                     ty,
@@ -3091,7 +3082,7 @@ mod size_asserts {
     use rustc_data_structures::static_assert_size;
     // tidy-alphabetical-start
     static_assert_size!(BasicBlockData<'_>, 144);
-    static_assert_size!(LocalDecl<'_>, 56);
+    static_assert_size!(LocalDecl<'_>, 40);
     static_assert_size!(Statement<'_>, 32);
     static_assert_size!(StatementKind<'_>, 16);
     static_assert_size!(Terminator<'_>, 112);
diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs
index 24fe3b47256..eb860c04de2 100644
--- a/compiler/rustc_middle/src/mir/patch.rs
+++ b/compiler/rustc_middle/src/mir/patch.rs
@@ -72,12 +72,12 @@ impl<'tcx> MirPatch<'tcx> {
         &mut self,
         ty: Ty<'tcx>,
         span: Span,
-        local_info: Option<Box<LocalInfo<'tcx>>>,
+        local_info: LocalInfo<'tcx>,
     ) -> Local {
         let index = self.next_local;
         self.next_local += 1;
         let mut new_decl = LocalDecl::new(ty, span).internal();
-        new_decl.local_info = local_info;
+        **new_decl.local_info.as_mut().assert_crate_local() = local_info;
         self.new_locals.push(new_decl);
         Local::new(index as usize)
     }
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index d85d68870d7..786c2e9cd94 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -2,8 +2,8 @@
 
 use crate::mir::{Body, ConstantKind, Promoted};
 use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::unord::UnordSet;
-use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -227,7 +227,7 @@ pub struct BorrowCheckResult<'tcx> {
     /// All the opaque types that are restricted to concrete types
     /// by this function. Unlike the value in `TypeckResults`, this has
     /// unerased regions.
-    pub concrete_opaque_types: VecMap<LocalDefId, OpaqueHiddenType<'tcx>>,
+    pub concrete_opaque_types: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
     pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
     pub used_mut_upvars: SmallVec<[Field; 8]>,
     pub tainted_by_errors: Option<ErrorGuaranteed>,
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 9312e27df37..3a893cdabf6 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -78,7 +78,8 @@ pub enum MirPhase {
     ///    MIR, this is UB.
     ///  - Retags: If `-Zmir-emit-retag` is enabled, analysis MIR has "implicit" retags in the same way
     ///    that Rust itself has them. Where exactly these are is generally subject to change, and so we
-    ///    don't document this here. Runtime MIR has all retags explicit.
+    ///    don't document this here. Runtime MIR has most retags explicit (though implicit retags
+    ///    can still occur at `Rvalue::{Ref,AddrOf}`).
     ///  - Generator bodies: In analysis MIR, locals may actually be behind a pointer that user code has
     ///    access to. This occurs in generator bodies. Such locals do not behave like other locals,
     ///    because they eg may be aliased in surprising ways. Runtime MIR has no such special locals -
@@ -646,8 +647,7 @@ pub enum TerminatorKind<'tcx> {
     /// When overflow checking is disabled and this is run-time MIR (as opposed to compile-time MIR
     /// that is used for CTFE), the following variants of this terminator behave as `goto target`:
     /// - `OverflowNeg(..)`,
-    /// - `Overflow(op, ..)` if op is a "checkable" operation (add, sub, mul, shl, shr, but NOT
-    /// div or rem).
+    /// - `Overflow(op, ..)` if op is add, sub, mul, shl, shr, but NOT div or rem.
     Assert {
         cond: Operand<'tcx>,
         expected: bool,
@@ -1081,11 +1081,7 @@ pub enum Rvalue<'tcx> {
     /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
     ///
     /// For addition, subtraction, and multiplication on integers the error condition is set when
-    /// the infinite precision result would be unequal to the actual result.
-    ///
-    /// For shift operations on integers the error condition is set when the value of right-hand
-    /// side is greater than or equal to the number of bits in the type of the left-hand side, or
-    /// when the value of right-hand side is negative.
+    /// the infinite precision result would not be equal to the actual result.
     ///
     /// Other combinations of types and operators are unsupported.
     CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
@@ -1170,7 +1166,7 @@ pub enum AggregateKind<'tcx> {
     Tuple,
 
     /// The second field is the variant index. It's equal to 0 for struct
-    /// and union expressions. The fourth field is
+    /// and union expressions. The last field is the
     /// active field number and is present only for union expressions
     /// -- e.g., for a union expression `SomeUnion { c: .. }`, the
     /// active field index would identity the field `c`
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index cbeacf21c19..cffdd7ff37f 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -804,7 +804,6 @@ macro_rules! make_mir_visitor {
                     source_info,
                     internal: _,
                     local_info: _,
-                    is_block_tail: _,
                 } = local_decl;
 
                 self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl {
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index 78ee8a6a8fd..ca65fbc2fd4 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -13,6 +13,10 @@ use rustc_query_system::query::{DefaultCacheSelector, SingleCacheSelector, VecCa
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
+/// Placeholder for `CrateNum`'s "local" counterpart
+#[derive(Copy, Clone, Debug)]
+pub struct LocalCrate;
+
 /// The `Key` trait controls what types can legally be used as the key
 /// for a query.
 pub trait Key: Sized {
@@ -26,10 +30,6 @@ pub trait Key: Sized {
     //      r-a issue: <https://github.com/rust-lang/rust-analyzer/issues/13693>
     type CacheSelector;
 
-    /// Given an instance of this key, what crate is it referring to?
-    /// This is used to find the provider.
-    fn query_crate_is_local(&self) -> bool;
-
     /// In the event that a cycle occurs, if no explicit span has been
     /// given for a query with key `self`, what span should we use?
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span;
@@ -45,14 +45,17 @@ pub trait Key: Sized {
     }
 }
 
+pub trait AsLocalKey: Key {
+    type LocalKey;
+
+    /// Given an instance of this key, what crate is it referring to?
+    /// This is used to find the provider.
+    fn as_local_key(&self) -> Option<Self::LocalKey>;
+}
+
 impl Key for () {
     type CacheSelector = SingleCacheSelector;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -61,23 +64,22 @@ impl Key for () {
 impl<'tcx> Key for ty::InstanceDef<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(self.def_id())
     }
 }
 
-impl<'tcx> Key for ty::Instance<'tcx> {
-    type CacheSelector = DefaultCacheSelector<Self>;
+impl<'tcx> AsLocalKey for ty::InstanceDef<'tcx> {
+    type LocalKey = Self;
 
     #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
+    fn as_local_key(&self) -> Option<Self::LocalKey> {
+        self.def_id().is_local().then(|| *self)
     }
+}
+
+impl<'tcx> Key for ty::Instance<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
 
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(self.def_id())
@@ -87,11 +89,6 @@ impl<'tcx> Key for ty::Instance<'tcx> {
 impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.instance.default_span(tcx)
     }
@@ -100,11 +97,6 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
 impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -113,11 +105,6 @@ impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
 impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -126,25 +113,27 @@ impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> {
 impl Key for CrateNum {
     type CacheSelector = VecCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        *self == LOCAL_CRATE
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
 }
 
-impl Key for OwnerId {
-    type CacheSelector = VecCacheSelector<Self>;
+impl AsLocalKey for CrateNum {
+    type LocalKey = LocalCrate;
 
     #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
+    fn as_local_key(&self) -> Option<Self::LocalKey> {
+        (*self == LOCAL_CRATE).then_some(LocalCrate)
     }
+}
+
+impl Key for OwnerId {
+    type CacheSelector = VecCacheSelector<Self>;
+
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.to_def_id().default_span(tcx)
     }
+
     fn key_as_def_id(&self) -> Option<DefId> {
         Some(self.to_def_id())
     }
@@ -153,13 +142,10 @@ impl Key for OwnerId {
 impl Key for LocalDefId {
     type CacheSelector = VecCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.to_def_id().default_span(tcx)
     }
+
     fn key_as_def_id(&self) -> Option<DefId> {
         Some(self.to_def_id())
     }
@@ -168,26 +154,28 @@ impl Key for LocalDefId {
 impl Key for DefId {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.krate == LOCAL_CRATE
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(*self)
     }
+
     #[inline(always)]
     fn key_as_def_id(&self) -> Option<DefId> {
         Some(*self)
     }
 }
 
-impl Key for ty::WithOptConstParam<LocalDefId> {
-    type CacheSelector = DefaultCacheSelector<Self>;
+impl AsLocalKey for DefId {
+    type LocalKey = LocalDefId;
 
     #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
+    fn as_local_key(&self) -> Option<Self::LocalKey> {
+        self.as_local()
     }
+}
+
+impl Key for ty::WithOptConstParam<LocalDefId> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.did.default_span(tcx)
     }
@@ -196,10 +184,6 @@ impl Key for ty::WithOptConstParam<LocalDefId> {
 impl Key for SimplifiedType {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -208,10 +192,6 @@ impl Key for SimplifiedType {
 impl Key for (DefId, DefId) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.0.krate == LOCAL_CRATE
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.1.default_span(tcx)
     }
@@ -220,10 +200,6 @@ impl Key for (DefId, DefId) {
 impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
     }
@@ -232,10 +208,6 @@ impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) {
 impl Key for (DefId, LocalDefId) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.0.krate == LOCAL_CRATE
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.1.default_span(tcx)
     }
@@ -244,10 +216,6 @@ impl Key for (DefId, LocalDefId) {
 impl Key for (LocalDefId, DefId) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
     }
@@ -256,10 +224,6 @@ impl Key for (LocalDefId, DefId) {
 impl Key for (LocalDefId, LocalDefId) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
     }
@@ -268,26 +232,19 @@ impl Key for (LocalDefId, LocalDefId) {
 impl Key for (DefId, Option<Ident>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.0.krate == LOCAL_CRATE
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(self.0)
     }
+
     #[inline(always)]
     fn key_as_def_id(&self) -> Option<DefId> {
         Some(self.0)
     }
 }
 
-impl Key for (DefId, LocalDefId, Ident) {
+impl Key for (LocalDefId, LocalDefId, Ident) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.0.krate == LOCAL_CRATE
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.1.default_span(tcx)
     }
@@ -296,34 +253,40 @@ impl Key for (DefId, LocalDefId, Ident) {
 impl Key for (CrateNum, DefId) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.0 == LOCAL_CRATE
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.1.default_span(tcx)
     }
 }
 
-impl Key for (CrateNum, SimplifiedType) {
-    type CacheSelector = DefaultCacheSelector<Self>;
+impl AsLocalKey for (CrateNum, DefId) {
+    type LocalKey = DefId;
 
     #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.0 == LOCAL_CRATE
+    fn as_local_key(&self) -> Option<Self::LocalKey> {
+        (self.0 == LOCAL_CRATE).then(|| self.1)
     }
+}
+
+impl Key for (CrateNum, SimplifiedType) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
 }
 
-impl Key for (DefId, SimplifiedType) {
-    type CacheSelector = DefaultCacheSelector<Self>;
+impl AsLocalKey for (CrateNum, SimplifiedType) {
+    type LocalKey = SimplifiedType;
 
     #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.0.krate == LOCAL_CRATE
+    fn as_local_key(&self) -> Option<Self::LocalKey> {
+        (self.0 == LOCAL_CRATE).then(|| self.1)
     }
+}
+
+impl Key for (DefId, SimplifiedType) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
     }
@@ -332,10 +295,6 @@ impl Key for (DefId, SimplifiedType) {
 impl<'tcx> Key for SubstsRef<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -344,10 +303,6 @@ impl<'tcx> Key for SubstsRef<'tcx> {
 impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.0.krate == LOCAL_CRATE
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
     }
@@ -356,10 +311,6 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
 impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        (self.0).def.did.krate == LOCAL_CRATE
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         (self.0).def.did.default_span(tcx)
     }
@@ -368,10 +319,6 @@ impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) {
 impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
     }
@@ -380,10 +327,6 @@ impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) {
 impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.1.def_id().krate == LOCAL_CRATE
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(self.1.def_id())
     }
@@ -392,10 +335,6 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
 impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -404,10 +343,6 @@ impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) {
 impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -416,10 +351,6 @@ impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> {
 impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.def_id().krate == LOCAL_CRATE
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(self.def_id())
     }
@@ -428,10 +359,6 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
 impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.def_id().krate == LOCAL_CRATE
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(self.def_id())
     }
@@ -440,10 +367,6 @@ impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> {
 impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.0.def_id().krate == LOCAL_CRATE
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(self.0.def_id())
     }
@@ -452,10 +375,6 @@ impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) {
 impl<'tcx> Key for GenericArg<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -464,10 +383,6 @@ impl<'tcx> Key for GenericArg<'tcx> {
 impl<'tcx> Key for mir::ConstantKind<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -476,10 +391,6 @@ impl<'tcx> Key for mir::ConstantKind<'tcx> {
 impl<'tcx> Key for ty::Const<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -488,13 +399,10 @@ impl<'tcx> Key for ty::Const<'tcx> {
 impl<'tcx> Key for Ty<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
+
     fn ty_adt_id(&self) -> Option<DefId> {
         match self.kind() {
             ty::Adt(adt, _) => Some(adt.did()),
@@ -506,10 +414,6 @@ impl<'tcx> Key for Ty<'tcx> {
 impl<'tcx> Key for TyAndLayout<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -518,10 +422,6 @@ impl<'tcx> Key for TyAndLayout<'tcx> {
 impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -530,10 +430,6 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
 impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -542,10 +438,6 @@ impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
 impl<'tcx> Key for ty::ParamEnv<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -554,10 +446,6 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> {
 impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        self.value.query_crate_is_local()
-    }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.value.default_span(tcx)
     }
@@ -566,10 +454,6 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
 impl Key for Symbol {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -578,10 +462,6 @@ impl Key for Symbol {
 impl Key for Option<Symbol> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
     fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -589,14 +469,9 @@ impl Key for Option<Symbol> {
 
 /// Canonical query goals correspond to abstract trait operations that
 /// are not tied to any crate in particular.
-impl<'tcx, T> Key for Canonical<'tcx, T> {
+impl<'tcx, T: Clone> Key for Canonical<'tcx, T> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -605,11 +480,6 @@ impl<'tcx, T> Key for Canonical<'tcx, T> {
 impl Key for (Symbol, u32, u32) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -618,11 +488,6 @@ impl Key for (Symbol, u32, u32) {
 impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -631,11 +496,6 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) {
 impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -644,11 +504,6 @@ impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) {
 impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -657,11 +512,6 @@ impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
 impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
     }
@@ -670,11 +520,6 @@ impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
 impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
@@ -683,11 +528,6 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) {
 impl Key for HirId {
     type CacheSelector = DefaultCacheSelector<Self>;
 
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
-
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.hir().span(*self)
     }
@@ -702,10 +542,6 @@ impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
     // Just forward to `Ty<'tcx>`
-    #[inline(always)]
-    fn query_crate_is_local(&self) -> bool {
-        true
-    }
 
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 75f05c4af23..f740ec51080 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -8,7 +8,7 @@ use crate::ty::{self, print::describe_as_module, TyCtxt};
 use rustc_span::def_id::LOCAL_CRATE;
 
 mod keys;
-pub use keys::Key;
+pub use keys::{AsLocalKey, Key, LocalCrate};
 
 // Each of these queries corresponds to a function pointer field in the
 // `Providers` struct for requesting a value of that type, and a method
@@ -191,6 +191,7 @@ rustc_queries! {
     {
         desc { "determine whether the opaque is a type-alias impl trait" }
         separate_provide_extern
+        feedable
     }
 
     query unsizing_params_for_adt(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32>
@@ -638,7 +639,7 @@ rustc_queries! {
 
     /// To avoid cycles within the predicates of a single item we compute
     /// per-type-parameter predicates for resolving `T::AssocTy`.
-    query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> {
+    query type_param_predicates(key: (LocalDefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> {
         desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) }
     }
 
@@ -784,7 +785,7 @@ rustc_queries! {
     /// if `fn_def_id` is the def id of a function defined inside an impl that implements a trait, then it
     /// creates and returns the associated items that correspond to each impl trait in return position
     /// of the implemented trait.
-    query associated_items_for_impl_trait_in_trait(fn_def_id: DefId) -> &'tcx [DefId] {
+    query associated_types_for_impl_traits_in_associated_fn(fn_def_id: DefId) -> &'tcx [DefId] {
         desc { |tcx| "creating associated items for impl trait in trait returned by `{}`", tcx.def_path_str(fn_def_id) }
         cache_on_disk_if { fn_def_id.is_local() }
         separate_provide_extern
@@ -792,10 +793,9 @@ rustc_queries! {
 
     /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding
     /// associated item.
-    query associated_item_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId {
+    query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId {
         desc { |tcx| "creates the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) }
         cache_on_disk_if { true }
-        separate_provide_extern
     }
 
     /// Given an `impl_id`, return the trait it implements.
@@ -2215,7 +2215,7 @@ rustc_queries! {
     }
 
     /// Used in `super_combine_consts` to ICE if the type of the two consts are definitely not going to end up being
-    /// equal to eachother. This might return `Ok` even if the types are unequal, but will never return `Err` if
+    /// equal to eachother. This might return `Ok` even if the types are not equal, but will never return `Err` if
     /// the types might be equal.
     query check_tys_might_be_eq(arg: Canonical<'tcx, (ty::ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>) -> Result<(), NoSolution> {
         desc { "check whether two const param are definitely not equal to eachother"}
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 6231dd9b6f5..833402abfc4 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -305,8 +305,6 @@ pub enum ObligationCauseCode<'tcx> {
     SizedReturnType,
     /// Yield type must be `Sized`.
     SizedYieldType,
-    /// Box expression result type must be `Sized`.
-    SizedBoxType,
     /// Inline asm operand type must be `Sized`.
     InlineAsmSized,
     /// `[expr; N]` requires `type_of(expr): Copy`.
@@ -899,6 +897,9 @@ pub enum ObjectSafetyViolation {
     /// (e.g., `trait Foo : Bar<Self>`).
     SupertraitSelf(SmallVec<[Span; 1]>),
 
+    // Supertrait has a non-lifetime `for<T>` binder.
+    SupertraitNonLifetimeBinder(SmallVec<[Span; 1]>),
+
     /// Method has something illegal.
     Method(Symbol, MethodViolationCode, Span),
 
@@ -921,6 +922,9 @@ impl ObjectSafetyViolation {
                         .into()
                 }
             }
+            ObjectSafetyViolation::SupertraitNonLifetimeBinder(_) => {
+                format!("where clause cannot reference non-lifetime `for<...>` variables").into()
+            }
             ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
                 format!("associated function `{}` has no `self` parameter", name).into()
             }
@@ -971,7 +975,9 @@ impl ObjectSafetyViolation {
 
     pub fn solution(&self, err: &mut Diagnostic) {
         match self {
-            ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {}
+            ObjectSafetyViolation::SizedSelf(_)
+            | ObjectSafetyViolation::SupertraitSelf(_)
+            | ObjectSafetyViolation::SupertraitNonLifetimeBinder(..) => {}
             ObjectSafetyViolation::Method(
                 name,
                 MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))),
@@ -1025,7 +1031,8 @@ impl ObjectSafetyViolation {
         // diagnostics use a `note` instead of a `span_label`.
         match self {
             ObjectSafetyViolation::SupertraitSelf(spans)
-            | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(),
+            | ObjectSafetyViolation::SizedSelf(spans)
+            | ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(),
             ObjectSafetyViolation::AssocConst(_, span)
             | ObjectSafetyViolation::GAT(_, span)
             | ObjectSafetyViolation::Method(_, _, span)
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 42101f6b931..bcedae233d9 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -4,7 +4,7 @@ use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
 use rustc_data_structures::intern::Interned;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_macros::HashStable;
 use std::fmt;
 
@@ -83,7 +83,7 @@ impl<'tcx> Const<'tcx> {
             None => tcx.mk_const(
                 ty::UnevaluatedConst {
                     def: def.to_global(),
-                    substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
+                    substs: InternalSubsts::identity_for_item(tcx, def.did),
                 },
                 ty,
             ),
@@ -265,8 +265,8 @@ impl<'tcx> Const<'tcx> {
     }
 }
 
-pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Const<'_>> {
-    let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) {
+pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Const<'_>> {
+    let default_def_id = match tcx.hir().get_by_def_id(def_id) {
         hir::Node::GenericParam(hir::GenericParam {
             kind: hir::GenericParamKind::Const { default: Some(ac), .. },
             ..
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index eecd78ab6c0..a7f38884ebc 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -237,7 +237,7 @@ impl ScalarInt {
     }
 
     /// Tries to convert the `ScalarInt` to an unsigned integer of the given size.
-    /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the
+    /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the
     /// `ScalarInt`s size in that case.
     #[inline]
     pub fn try_to_uint(self, size: Size) -> Result<u128, Size> {
@@ -297,7 +297,7 @@ impl ScalarInt {
     }
 
     /// Tries to convert the `ScalarInt` to a signed integer of the given size.
-    /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the
+    /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the
     /// `ScalarInt`s size in that case.
     #[inline]
     pub fn try_to_int(self, size: Size) -> Result<i128, Size> {
@@ -306,35 +306,35 @@ impl ScalarInt {
     }
 
     /// Tries to convert the `ScalarInt` to i8.
-    /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 1 }`
+    /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 1 }`
     /// and returns the `ScalarInt`s size in that case.
     pub fn try_to_i8(self) -> Result<i8, Size> {
         self.try_to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap())
     }
 
     /// Tries to convert the `ScalarInt` to i16.
-    /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 2 }`
+    /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 2 }`
     /// and returns the `ScalarInt`s size in that case.
     pub fn try_to_i16(self) -> Result<i16, Size> {
         self.try_to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap())
     }
 
     /// Tries to convert the `ScalarInt` to i32.
-    /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 4 }`
+    /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 4 }`
     /// and returns the `ScalarInt`s size in that case.
     pub fn try_to_i32(self) -> Result<i32, Size> {
         self.try_to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap())
     }
 
     /// Tries to convert the `ScalarInt` to i64.
-    /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 8 }`
+    /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 8 }`
     /// and returns the `ScalarInt`s size in that case.
     pub fn try_to_i64(self) -> Result<i64, Size> {
         self.try_to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap())
     }
 
     /// Tries to convert the `ScalarInt` to i128.
-    /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 16 }`
+    /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 16 }`
     /// and returns the `ScalarInt`s size in that case.
     pub fn try_to_i128(self) -> Result<i128, Size> {
         self.try_to_int(Size::from_bits(128)).map(|v| i128::try_from(v).unwrap())
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index d5ba0785fa6..65376335398 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -15,6 +15,7 @@ use crate::mir::interpret::{self, Allocation, ConstAllocation};
 use crate::mir::{
     Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
 };
+use crate::query::LocalCrate;
 use crate::thir::Thir;
 use crate::traits;
 use crate::traits::solve;
@@ -71,6 +72,7 @@ use rustc_type_ir::WithCachedTypeInfo;
 use rustc_type_ir::{CollectAndApply, DynKind, Interner, TypeFlags};
 
 use std::any::Any;
+use std::assert_matches::debug_assert_matches;
 use std::borrow::Borrow;
 use std::cmp::Ordering;
 use std::fmt;
@@ -2049,6 +2051,12 @@ impl<'tcx> TyCtxt<'tcx> {
 
     #[inline]
     pub fn mk_alias(self, kind: ty::AliasKind, alias_ty: ty::AliasTy<'tcx>) -> Ty<'tcx> {
+        debug_assert_matches!(
+            (kind, self.def_kind(alias_ty.def_id)),
+            (ty::Opaque, DefKind::OpaqueTy)
+                | (ty::Projection, DefKind::AssocTy)
+                | (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder)
+        );
         self.mk_ty_from_kind(Alias(kind, alias_ty))
     }
 
@@ -2511,16 +2519,11 @@ pub fn provide(providers: &mut ty::query::Providers) {
 
     providers.extern_mod_stmt_cnum =
         |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
-    providers.is_panic_runtime = |tcx, cnum| {
-        assert_eq!(cnum, LOCAL_CRATE);
-        tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime)
-    };
-    providers.is_compiler_builtins = |tcx, cnum| {
-        assert_eq!(cnum, LOCAL_CRATE);
-        tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins)
-    };
-    providers.has_panic_handler = |tcx, cnum| {
-        assert_eq!(cnum, LOCAL_CRATE);
+    providers.is_panic_runtime =
+        |tcx, LocalCrate| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime);
+    providers.is_compiler_builtins =
+        |tcx, LocalCrate| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins);
+    providers.has_panic_handler = |tcx, LocalCrate| {
         // We want to check if the panic handler was defined in this crate
         tcx.lang_items().panic_impl().map_or(false, |did| did.is_local())
     };
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index d66f436f947..6205e2bf24d 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -51,9 +51,7 @@ where
 // Region folder
 
 impl<'tcx> TyCtxt<'tcx> {
-    /// Folds the escaping and free regions in `value` using `f`, and
-    /// sets `skipped_regions` to true if any late-bound region was found
-    /// and skipped.
+    /// Folds the escaping and free regions in `value` using `f`.
     pub fn fold_regions<T>(
         self,
         value: T,
@@ -64,17 +62,6 @@ impl<'tcx> TyCtxt<'tcx> {
     {
         value.fold_with(&mut RegionFolder::new(self, &mut f))
     }
-
-    pub fn super_fold_regions<T>(
-        self,
-        value: T,
-        mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>,
-    ) -> T
-    where
-        T: TypeSuperFoldable<TyCtxt<'tcx>>,
-    {
-        value.super_fold_with(&mut RegionFolder::new(self, &mut f))
-    }
 }
 
 /// Folds over the substructure of a type, visiting its component
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index f4028a5a9f6..aa10a651c07 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -187,7 +187,11 @@ impl<'tcx> InstanceDef<'tcx> {
     }
 
     #[inline]
-    pub fn get_attrs(&self, tcx: TyCtxt<'tcx>, attr: Symbol) -> ty::Attributes<'tcx> {
+    pub fn get_attrs(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        attr: Symbol,
+    ) -> impl Iterator<Item = &'tcx rustc_ast::Attribute> {
         tcx.get_attrs(self.def_id(), attr)
     }
 
@@ -781,6 +785,12 @@ fn needs_fn_once_adapter_shim(
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Decodable, Encodable, HashStable)]
 pub struct UnusedGenericParams(FiniteBitSet<u32>);
 
+impl Default for UnusedGenericParams {
+    fn default() -> Self {
+        UnusedGenericParams::new_all_used()
+    }
+}
+
 impl UnusedGenericParams {
     pub fn new_all_unused(amount: u32) -> Self {
         let mut bitset = FiniteBitSet::new_empty();
@@ -807,4 +817,12 @@ impl UnusedGenericParams {
     pub fn all_used(&self) -> bool {
         self.0.is_empty()
     }
+
+    pub fn bits(&self) -> u32 {
+        self.0.0
+    }
+
+    pub fn from_bits(bits: u32) -> UnusedGenericParams {
+        UnusedGenericParams(FiniteBitSet(bits))
+    }
 }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 254ffc33c96..42fb5d031bb 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -730,7 +730,11 @@ where
                         */
                     };
 
-                    let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
+                    let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type()
+                        // Projection eagerly bails out when the pointee references errors,
+                        // fall back to structurally deducing metadata.
+                        && !pointee.references_error()
+                    {
                         let metadata = tcx.normalize_erasing_regions(
                             cx.param_env(),
                             tcx.mk_projection(metadata_def_id, [pointee]),
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 04d7de531c2..d383a413208 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1128,6 +1128,13 @@ impl<'tcx, T> ToPredicate<'tcx, T> for T {
     }
 }
 
+impl<'tcx> ToPredicate<'tcx> for PredicateKind<'tcx> {
+    #[inline(always)]
+    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        ty::Binder::dummy(self).to_predicate(tcx)
+    }
+}
+
 impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> {
     #[inline(always)]
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
@@ -1142,6 +1149,13 @@ impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> {
     }
 }
 
+impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
+    #[inline(always)]
+    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        ty::Binder::dummy(self).to_predicate(tcx)
+    }
+}
+
 impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
     #[inline(always)]
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
@@ -1385,7 +1399,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
         // lifetimes with 'static and remapping only those used in the
         // `impl Trait` return type, resulting in the parameters
         // shifting.
-        let id_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+        let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
         debug!(?id_substs);
 
         // This zip may have several times the same lifetime in `substs` paired with a different
@@ -2027,7 +2041,6 @@ impl<'tcx> FieldDef {
     }
 }
 
-pub type Attributes<'tcx> = impl Iterator<Item = &'tcx ast::Attribute>;
 #[derive(Debug, PartialEq, Eq)]
 pub enum ImplOverlapKind {
     /// These impls are always allowed to overlap.
@@ -2375,7 +2388,12 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Gets all attributes with the given name.
-    pub fn get_attrs(self, did: DefId, attr: Symbol) -> ty::Attributes<'tcx> {
+    pub fn get_attrs(
+        self,
+        did: impl Into<DefId>,
+        attr: Symbol,
+    ) -> impl Iterator<Item = &'tcx ast::Attribute> {
+        let did: DefId = did.into();
         let filter_fn = move |a: &&ast::Attribute| a.has_name(attr);
         if let Some(did) = did.as_local() {
             self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn)
@@ -2386,8 +2404,9 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> {
+    pub fn get_attr(self, did: impl Into<DefId>, attr: Symbol) -> Option<&'tcx ast::Attribute> {
         if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) {
+            let did: DefId = did.into();
             bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr);
         } else {
             self.get_attrs(did, attr).next()
@@ -2395,7 +2414,8 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Determines whether an item is annotated with an attribute.
-    pub fn has_attr(self, did: DefId, attr: Symbol) -> bool {
+    pub fn has_attr(self, did: impl Into<DefId>, attr: Symbol) -> bool {
+        let did: DefId = did.into();
         if cfg!(debug_assertions) && !did.is_local() && rustc_feature::is_builtin_only_local(attr) {
             bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr);
         } else {
@@ -2552,12 +2572,18 @@ impl<'tcx> TyCtxt<'tcx> {
         matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait))
     }
 
-    pub fn impl_trait_in_trait_parent(self, mut def_id: DefId) -> DefId {
-        while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn {
-            debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder);
-            def_id = self.parent(def_id);
+    pub fn impl_trait_in_trait_parent_fn(self, mut def_id: DefId) -> DefId {
+        match self.opt_rpitit_info(def_id) {
+            Some(ImplTraitInTraitData::Trait { fn_def_id, .. })
+            | Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) => fn_def_id,
+            None => {
+                while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn {
+                    debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder);
+                    def_id = self.parent(def_id);
+                }
+                def_id
+            }
         }
-        def_id
     }
 
     pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool {
@@ -2572,6 +2598,12 @@ impl<'tcx> TyCtxt<'tcx> {
 
         let Some(trait_item_def_id) = item.trait_item_def_id else { return false; };
 
+        if self.lower_impl_trait_in_trait_to_assoc_ty() {
+            return !self
+                .associated_types_for_impl_traits_in_associated_fn(trait_item_def_id)
+                .is_empty();
+        }
+
         // FIXME(RPITIT): This does a somewhat manual walk through the signature
         // of the trait fn to look for any RPITITs, but that's kinda doing a lot
         // of work. We can probably remove this when we refactor RPITITs to be
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 8849e7eab33..7534d06ae91 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -63,6 +63,7 @@ trivially_parameterized_over_tcx! {
     ty::DeducedParamAttrs,
     ty::Generics,
     ty::ImplPolarity,
+    ty::ImplTraitInTraitData,
     ty::ReprOptions,
     ty::TraitDef,
     ty::UnusedGenericParams,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index b3139d23d36..fffdbfc9660 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -728,7 +728,7 @@ pub trait PrettyPrinter<'tcx>:
             }
             ty::Alias(ty::Projection, ref data) => {
                 if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get()))
-                    && self.tcx().def_kind(data.def_id) == DefKind::ImplTraitPlaceholder
+                    && self.tcx().is_impl_trait_in_trait(data.def_id)
                 {
                     return self.pretty_print_opaque_impl_type(data.def_id, data.substs);
                 } else {
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 05219efe5f5..30246fe4dbe 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -17,7 +17,7 @@ use crate::mir::interpret::{
 };
 use crate::mir::interpret::{LitToConstError, LitToConstInput};
 use crate::mir::mono::CodegenUnit;
-use crate::query::Key;
+use crate::query::{AsLocalKey, Key};
 use crate::thir;
 use crate::traits::query::{
     CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
@@ -151,6 +151,20 @@ macro_rules! query_if_arena {
     };
 }
 
+/// If `separate_provide_if_extern`, then the key can be projected to its
+/// local key via `<$K as AsLocalKey>::LocalKey`.
+macro_rules! local_key_if_separate_extern {
+    ([] $($K:tt)*) => {
+        $($K)*
+    };
+    ([(separate_provide_extern) $($rest:tt)*] $($K:tt)*) => {
+        <$($K)* as AsLocalKey>::LocalKey
+    };
+    ([$other:tt $($modifiers:tt)*] $($K:tt)*) => {
+        local_key_if_separate_extern!([$($modifiers)*] $($K)*)
+    };
+}
+
 macro_rules! separate_provide_extern_decl {
     ([][$name:ident]) => {
         ()
@@ -212,6 +226,12 @@ macro_rules! define_callbacks {
             $(pub type $name<'tcx> = $($K)*;)*
         }
         #[allow(nonstandard_style, unused_lifetimes)]
+        pub mod query_keys_local {
+            use super::*;
+
+            $(pub type $name<'tcx> = local_key_if_separate_extern!([$($modifiers)*] $($K)*);)*
+        }
+        #[allow(nonstandard_style, unused_lifetimes)]
         pub mod query_values {
             use super::*;
 
@@ -385,7 +405,7 @@ macro_rules! define_callbacks {
         pub struct Providers {
             $(pub $name: for<'tcx> fn(
                 TyCtxt<'tcx>,
-                query_keys::$name<'tcx>,
+                query_keys_local::$name<'tcx>,
             ) -> query_provided::$name<'tcx>,)*
         }
 
@@ -395,17 +415,14 @@ macro_rules! define_callbacks {
 
         impl Default for Providers {
             fn default() -> Self {
-                use crate::query::Key;
-
                 Providers {
                     $($name: |_, key| bug!(
-                        "`tcx.{}({:?})` is not supported for {} crate;\n\
+                        "`tcx.{}({:?})` is not supported for this key;\n\
                         hint: Queries can be either made to the local crate, or the external crate. \
                         This error means you tried to use it for one that's not supported.\n\
                         If that's not the case, {} was likely never assigned to a provider function.\n",
                         stringify!($name),
                         key,
-                        if key.query_crate_is_local() { "local" } else { "external" },
                         stringify!($name),
                     ),)*
                 }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 52d114bae30..2a0536a1af7 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -23,7 +23,7 @@ use rustc_macros::HashStable;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
-use rustc_target::spec::abi;
+use rustc_target::spec::abi::{self, Abi};
 use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::fmt;
@@ -1288,7 +1288,7 @@ impl<'tcx> AliasTy<'tcx> {
         match tcx.def_kind(self.def_id) {
             DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
             DefKind::ImplTraitPlaceholder => {
-                tcx.parent(tcx.impl_trait_in_trait_parent(self.def_id))
+                tcx.parent(tcx.impl_trait_in_trait_parent_fn(self.def_id))
             }
             kind => bug!("expected a projection AliasTy; found {kind:?}"),
         }
@@ -1403,6 +1403,18 @@ impl<'tcx> PolyFnSig<'tcx> {
     pub fn abi(&self) -> abi::Abi {
         self.skip_binder().abi
     }
+
+    pub fn is_fn_trait_compatible(&self) -> bool {
+        matches!(
+            self.skip_binder(),
+            ty::FnSig {
+                unsafety: rustc_hir::Unsafety::Normal,
+                abi: Abi::Rust,
+                c_variadic: false,
+                ..
+            }
+        )
+    }
 }
 
 pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>;
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index b090bd9d807..f05b873432d 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -302,8 +302,8 @@ impl<'tcx> InternalSubsts<'tcx> {
     }
 
     /// Creates an `InternalSubsts` that maps each generic parameter to itself.
-    pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
-        Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param))
+    pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: impl Into<DefId>) -> SubstsRef<'tcx> {
+        Self::for_item(tcx, def_id.into(), |param, _| tcx.mk_param_from_def(param))
     }
 
     /// Creates an `InternalSubsts` for generic parameter definitions,
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 586958247fc..2b0fb4dc2b7 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -8,10 +8,9 @@ use crate::{
     },
 };
 use rustc_data_structures::{
-    fx::FxHashMap,
+    fx::{FxHashMap, FxIndexMap},
     sync::Lrc,
     unord::{UnordItems, UnordSet},
-    vec_map::VecMap,
 };
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
@@ -155,7 +154,7 @@ pub struct TypeckResults<'tcx> {
     /// by this function. We also store the
     /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
     /// even if they are only set in dead code (which doesn't show up in MIR).
-    pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
+    pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
 
     /// Tracks the minimum captures required for a closure;
     /// see `MinCaptureInformationMap` for more details.
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index b0f6127baa5..dcd9743196e 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -15,7 +15,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable;
@@ -60,22 +60,13 @@ impl<'tcx> fmt::Display for Discr<'tcx> {
     }
 }
 
-fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) {
-    let (int, signed) = match *ty.kind() {
-        ty::Int(ity) => (Integer::from_int_ty(&tcx, ity), true),
-        ty::Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false),
-        _ => bug!("non integer discriminant"),
-    };
-    (int.size(), signed)
-}
-
 impl<'tcx> Discr<'tcx> {
     /// Adds `1` to the value and wraps around if the maximum for the type is reached.
     pub fn wrap_incr(self, tcx: TyCtxt<'tcx>) -> Self {
         self.checked_add(tcx, 1).0
     }
     pub fn checked_add(self, tcx: TyCtxt<'tcx>, n: u128) -> (Self, bool) {
-        let (size, signed) = int_size_and_signed(tcx, self.ty);
+        let (size, signed) = self.ty.int_size_and_signed(tcx);
         let (val, oflo) = if signed {
             let min = size.signed_int_min();
             let max = size.signed_int_max();
@@ -929,12 +920,21 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
 }
 
 impl<'tcx> Ty<'tcx> {
+    pub fn int_size_and_signed(self, tcx: TyCtxt<'tcx>) -> (Size, bool) {
+        let (int, signed) = match *self.kind() {
+            ty::Int(ity) => (Integer::from_int_ty(&tcx, ity), true),
+            ty::Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false),
+            _ => bug!("non integer discriminant"),
+        };
+        (int.size(), signed)
+    }
+
     /// Returns the maximum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
     pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
         let val = match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
-                let (size, signed) = int_size_and_signed(tcx, self);
+                let (size, signed) = self.int_size_and_signed(tcx);
                 let val =
                     if signed { size.signed_int_max() as u128 } else { size.unsigned_int_max() };
                 Some(val)
@@ -955,7 +955,7 @@ impl<'tcx> Ty<'tcx> {
     pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
         let val = match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
-                let (size, signed) = int_size_and_signed(tcx, self);
+                let (size, signed) = self.int_size_and_signed(tcx);
                 let val = if signed { size.truncate(size.signed_int_min() as u128) } else { 0 };
                 Some(val)
             }
@@ -1439,8 +1439,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>(
 }
 
 /// Determines whether an item is annotated with `doc(hidden)`.
-fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    assert!(def_id.is_local());
+fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     tcx.get_attrs(def_id, sym::doc)
         .filter_map(|attr| attr.meta_item_list())
         .any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
@@ -1454,7 +1453,7 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 }
 
 /// Determines whether an item is an intrinsic by Abi.
-pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
 }
 
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 5e77f2dc126..adbd37a7cd9 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -166,6 +166,28 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
                 let cast_kind = mir_cast_kind(source_ty, expr.ty);
                 Ok(Rvalue::Cast(cast_kind, source, expr.ty))
             },
+            ExprKind::Tuple { fields } => Ok(
+                Rvalue::Aggregate(
+                    Box::new(AggregateKind::Tuple),
+                    fields.iter().map(|e| self.parse_operand(*e)).collect::<Result<_, _>>()?
+                )
+            ),
+            ExprKind::Array { fields } => {
+                let elem_ty = expr.ty.builtin_index().expect("ty must be an array");
+                Ok(Rvalue::Aggregate(
+                    Box::new(AggregateKind::Array(elem_ty)),
+                    fields.iter().map(|e| self.parse_operand(*e)).collect::<Result<_, _>>()?
+                ))
+            },
+            ExprKind::Adt(box AdtExpr{ adt_def, variant_index, substs, fields, .. }) => {
+                let is_union = adt_def.is_union();
+                let active_field_index = is_union.then(|| fields[0].name.index());
+
+                Ok(Rvalue::Aggregate(
+                    Box::new(AggregateKind::Adt(adt_def.did(), *variant_index, substs, None, active_field_index)),
+                    fields.iter().map(|f| self.parse_operand(f.expr)).collect::<Result<_, _>>()?
+                ))
+            },
             _ => self.parse_operand(expr_id).map(Rvalue::Use),
         )
     }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index ff3198847df..6941da331fc 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -20,7 +20,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         expr: &Expr<'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         let local_scope = self.local_scope();
-        self.as_operand(block, Some(local_scope), expr, None, NeedsTemporary::Maybe)
+        self.as_operand(block, Some(local_scope), expr, LocalInfo::Boring, NeedsTemporary::Maybe)
     }
 
     /// Returns an operand suitable for use until the end of the current scope expression and
@@ -102,7 +102,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         mut block: BasicBlock,
         scope: Option<region::Scope>,
         expr: &Expr<'tcx>,
-        local_info: Option<Box<LocalInfo<'tcx>>>,
+        local_info: LocalInfo<'tcx>,
         needs_temporary: NeedsTemporary,
     ) -> BlockAnd<Operand<'tcx>> {
         let this = self;
@@ -124,8 +124,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             Category::Constant | Category::Place | Category::Rvalue(..) => {
                 let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
-                if this.local_decls[operand].local_info.is_none() {
-                    this.local_decls[operand].local_info = local_info;
+                // Overwrite temp local info if we have something more interesting to record.
+                if !matches!(local_info, LocalInfo::Boring) {
+                    let decl_info = this.local_decls[operand].local_info.as_mut().assert_crate_local();
+                    if let LocalInfo::Boring | LocalInfo::BlockTailTemp(_) = **decl_info {
+                        **decl_info = local_info;
+                    }
                 }
                 block.and(Operand::Move(Place::from(operand)))
             }
@@ -178,6 +182,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
         }
 
-        this.as_operand(block, scope, expr, None, NeedsTemporary::Maybe)
+        this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::Maybe)
     }
 }
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 a4e48c1545d..140d1154718 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -9,6 +9,7 @@ use crate::build::expr::category::{Category, RvalueFunc};
 use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::AssertKind;
 use rustc_middle::mir::Place;
 use rustc_middle::mir::*;
@@ -63,7 +64,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             block,
                             scope,
                             &this.thir[value],
-                            None,
+                            LocalInfo::Boring,
                             NeedsTemporary::No
                         )
                     );
@@ -72,19 +73,34 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             ExprKind::Binary { op, lhs, rhs } => {
                 let lhs = unpack!(
-                    block =
-                        this.as_operand(block, scope, &this.thir[lhs], None, NeedsTemporary::Maybe)
+                    block = this.as_operand(
+                        block,
+                        scope,
+                        &this.thir[lhs],
+                        LocalInfo::Boring,
+                        NeedsTemporary::Maybe
+                    )
                 );
                 let rhs = unpack!(
-                    block =
-                        this.as_operand(block, scope, &this.thir[rhs], None, NeedsTemporary::No)
+                    block = this.as_operand(
+                        block,
+                        scope,
+                        &this.thir[rhs],
+                        LocalInfo::Boring,
+                        NeedsTemporary::No
+                    )
                 );
                 this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
             }
             ExprKind::Unary { op, arg } => {
                 let arg = unpack!(
-                    block =
-                        this.as_operand(block, scope, &this.thir[arg], None, NeedsTemporary::No)
+                    block = this.as_operand(
+                        block,
+                        scope,
+                        &this.thir[arg],
+                        LocalInfo::Boring,
+                        NeedsTemporary::No
+                    )
                 );
                 // Check for -MIN on signed integers
                 if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
@@ -259,7 +275,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 } else {
                     let ty = source.ty;
                     let source = unpack!(
-                        block = this.as_operand(block, scope, source, None, NeedsTemporary::No)
+                        block = this.as_operand(block, scope, source, LocalInfo::Boring, NeedsTemporary::No)
                     );
                     (source, ty)
                 };
@@ -271,8 +287,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             ExprKind::Pointer { cast, source } => {
                 let source = unpack!(
-                    block =
-                        this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No)
+                    block = this.as_operand(
+                        block,
+                        scope,
+                        &this.thir[source],
+                        LocalInfo::Boring,
+                        NeedsTemporary::No
+                    )
                 );
                 block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
             }
@@ -314,7 +335,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 block,
                                 scope,
                                 &this.thir[f],
-                                None,
+                                LocalInfo::Boring,
                                 NeedsTemporary::Maybe
                             )
                         )
@@ -335,7 +356,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 block,
                                 scope,
                                 &this.thir[f],
-                                None,
+                                LocalInfo::Boring,
                                 NeedsTemporary::Maybe
                             )
                         )
@@ -423,7 +444,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                                 block,
                                                 scope,
                                                 upvar,
-                                                None,
+                                                LocalInfo::Boring,
                                                 NeedsTemporary::Maybe
                                             )
                                         )
@@ -501,8 +522,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     Category::of(&expr.kind),
                     Some(Category::Rvalue(RvalueFunc::AsRvalue) | Category::Constant)
                 ));
-                let operand =
-                    unpack!(block = this.as_operand(block, scope, expr, None, NeedsTemporary::No));
+                let operand = unpack!(
+                    block =
+                        this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No)
+                );
                 block.and(Rvalue::Use(operand))
             }
         }
@@ -519,30 +542,68 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ) -> BlockAnd<Rvalue<'tcx>> {
         let source_info = self.source_info(span);
         let bool_ty = self.tcx.types.bool;
-        if self.check_overflow && op.is_checkable() && ty.is_integral() {
-            let result_tup = self.tcx.mk_tup(&[ty, bool_ty]);
-            let result_value = self.temp(result_tup, span);
-
-            self.cfg.push_assign(
-                block,
-                source_info,
-                result_value,
-                Rvalue::CheckedBinaryOp(op, Box::new((lhs.to_copy(), rhs.to_copy()))),
-            );
-            let val_fld = Field::new(0);
-            let of_fld = Field::new(1);
+        let rvalue = match op {
+            BinOp::Add | BinOp::Sub | BinOp::Mul if self.check_overflow && ty.is_integral() => {
+                let result_tup = self.tcx.mk_tup(&[ty, bool_ty]);
+                let result_value = self.temp(result_tup, span);
 
-            let tcx = self.tcx;
-            let val = tcx.mk_place_field(result_value, val_fld, ty);
-            let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
+                self.cfg.push_assign(
+                    block,
+                    source_info,
+                    result_value,
+                    Rvalue::CheckedBinaryOp(op, Box::new((lhs.to_copy(), rhs.to_copy()))),
+                );
+                let val_fld = Field::new(0);
+                let of_fld = Field::new(1);
 
-            let err = AssertKind::Overflow(op, lhs, rhs);
+                let tcx = self.tcx;
+                let val = tcx.mk_place_field(result_value, val_fld, ty);
+                let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
 
-            block = self.assert(block, Operand::Move(of), false, err, span);
+                let err = AssertKind::Overflow(op, lhs, rhs);
+                block = self.assert(block, Operand::Move(of), false, err, span);
 
-            block.and(Rvalue::Use(Operand::Move(val)))
-        } else {
-            if ty.is_integral() && (op == BinOp::Div || op == BinOp::Rem) {
+                Rvalue::Use(Operand::Move(val))
+            }
+            BinOp::Shl | BinOp::Shr if self.check_overflow && ty.is_integral() => {
+                // Consider that the shift overflows if `rhs < 0` or `rhs >= bits`.
+                // This can be encoded as a single operation as `(rhs & -bits) != 0`.
+                let (size, _) = ty.int_size_and_signed(self.tcx);
+                let bits = size.bits();
+                debug_assert!(bits.is_power_of_two());
+                let mask = !((bits - 1) as u128);
+
+                let rhs_ty = rhs.ty(&self.local_decls, self.tcx);
+                let (rhs_size, _) = rhs_ty.int_size_and_signed(self.tcx);
+                let mask = Operand::const_from_scalar(
+                    self.tcx,
+                    rhs_ty,
+                    Scalar::from_uint(rhs_size.truncate(mask), rhs_size),
+                    span,
+                );
+
+                let outer_bits = self.temp(rhs_ty, span);
+                self.cfg.push_assign(
+                    block,
+                    source_info,
+                    outer_bits,
+                    Rvalue::BinaryOp(BinOp::BitAnd, Box::new((rhs.to_copy(), mask))),
+                );
+
+                let overflows = self.temp(bool_ty, span);
+                let zero = self.zero_literal(span, rhs_ty);
+                self.cfg.push_assign(
+                    block,
+                    source_info,
+                    overflows,
+                    Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Move(outer_bits), zero))),
+                );
+
+                let overflow_err = AssertKind::Overflow(op, lhs.to_copy(), rhs.to_copy());
+                block = self.assert(block, Operand::Move(overflows), false, overflow_err, span);
+                Rvalue::BinaryOp(op, Box::new((lhs, rhs)))
+            }
+            BinOp::Div | BinOp::Rem if ty.is_integral() => {
                 // Checking division and remainder is more complex, since we 1. always check
                 // and 2. there are two possible failure cases, divide-by-zero and overflow.
 
@@ -601,10 +662,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                     block = self.assert(block, Operand::Move(of), false, overflow_err, span);
                 }
-            }
 
-            block.and(Rvalue::BinaryOp(op, Box::new((lhs, rhs))))
-        }
+                Rvalue::BinaryOp(op, Box::new((lhs, rhs)))
+            }
+            _ => Rvalue::BinaryOp(op, Box::new((lhs, rhs))),
+        };
+        block.and(rvalue)
     }
 
     fn build_zero_repeat(
@@ -621,8 +684,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // Repeating a const does nothing
         } else {
             // For a non-const, we may need to generate an appropriate `Drop`
-            let value_operand =
-                unpack!(block = this.as_operand(block, scope, value, None, NeedsTemporary::No));
+            let value_operand = unpack!(
+                block = this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No)
+            );
             if let Operand::Move(to_drop) = value_operand {
                 let success = this.cfg.start_new_block();
                 this.cfg.terminate(
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index 3d3cf75559e..c8910c272b1 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -49,29 +49,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context);
-            // Find out whether this temp is being created within the
-            // tail expression of a block whose result is ignored.
-            if let Some(tail_info) = this.block_context.currently_in_block_tail() {
-                local_decl = local_decl.block_tail(tail_info);
-            }
-            match expr.kind {
+            let local_info = match expr.kind {
                 ExprKind::StaticRef { def_id, .. } => {
                     assert!(!this.tcx.is_thread_local_static(def_id));
                     local_decl.internal = true;
-                    local_decl.local_info =
-                        Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: false }));
+                    LocalInfo::StaticRef { def_id, is_thread_local: false }
                 }
                 ExprKind::ThreadLocalRef(def_id) => {
                     assert!(this.tcx.is_thread_local_static(def_id));
                     local_decl.internal = true;
-                    local_decl.local_info =
-                        Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: true }));
+                    LocalInfo::StaticRef { def_id, is_thread_local: true }
                 }
                 ExprKind::NamedConst { def_id, .. } | ExprKind::ConstParam { def_id, .. } => {
-                    local_decl.local_info = Some(Box::new(LocalInfo::ConstRef { def_id }));
+                    LocalInfo::ConstRef { def_id }
                 }
-                _ => {}
-            }
+                // Find out whether this temp is being created within the
+                // tail expression of a block whose result is ignored.
+                _ if let Some(tail_info) = this.block_context.currently_in_block_tail() => {
+                    LocalInfo::BlockTailTemp(tail_info)
+                }
+                _ => LocalInfo::Boring,
+            };
+            **local_decl.local_info.as_mut().assert_crate_local() = local_info;
             this.local_decls.push(local_decl)
         };
         let temp_place = Place::from(temp);
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index dac9bf0a883..ebe8ea25ad3 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -328,7 +328,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let fields_map: FxHashMap<_, _> = fields
                     .into_iter()
                     .map(|f| {
-                        let local_info = Box::new(LocalInfo::AggregateTemp);
                         (
                             f.name,
                             unpack!(
@@ -336,7 +335,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                     block,
                                     Some(scope),
                                     &this.thir[f.expr],
-                                    Some(local_info),
+                                    LocalInfo::AggregateTemp,
                                     NeedsTemporary::Maybe,
                                 )
                             ),
@@ -526,7 +525,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         block,
                         Some(scope),
                         &this.thir[value],
-                        None,
+                        LocalInfo::Boring,
                         NeedsTemporary::No
                     )
                 );
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 3fb8a6db2d2..2d52102db2c 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -607,9 +607,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     // };
                     // ```
                     if let Some(place) = initializer.try_to_place(self) {
-                        let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+                        let LocalInfo::User(BindingForm::Var(
                             VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
-                        )))) = self.local_decls[local].local_info else {
+                        )) = **self.local_decls[local].local_info.as_mut().assert_crate_local() else {
                             bug!("Let binding to non-user variable.")
                         };
                         *match_place = Some(place);
@@ -1754,7 +1754,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
                 let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span);
                 fake_borrow_temp.internal = self.local_decls[matched_place.local].internal;
-                fake_borrow_temp.local_info = Some(Box::new(LocalInfo::FakeBorrow));
+                fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow));
                 let fake_borrow_temp = self.local_decls.push(fake_borrow_temp);
 
                 (matched_place, fake_borrow_temp)
@@ -2224,8 +2224,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) },
             source_info,
             internal: false,
-            is_block_tail: None,
-            local_info: Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+            local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::Var(
                 VarBindingForm {
                     binding_mode,
                     // hypothetically, `visit_primary_bindings` could try to unzip
@@ -2236,7 +2235,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     opt_match_place,
                     pat_span,
                 },
-            ))))),
+            )))),
         };
         let for_arm_body = self.local_decls.push(local);
         self.var_debug_info.push(VarDebugInfo {
@@ -2253,10 +2252,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 user_ty: None,
                 source_info,
                 internal: false,
-                is_block_tail: None,
-                local_info: Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(
+                local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(
                     BindingForm::RefForGuard,
-                )))),
+                ))),
             });
             self.var_debug_info.push(VarDebugInfo {
                 name,
diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs
index baeb2718cae..90d78658f96 100644
--- a/compiler/rustc_mir_build/src/build/misc.rs
+++ b/compiler/rustc_mir_build/src/build/misc.rs
@@ -5,7 +5,7 @@ use crate::build::Builder;
 
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -66,7 +66,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub(crate) fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> {
         let tcx = self.tcx;
         let ty = place.ty(&self.local_decls, tcx).ty;
-        if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) {
+        if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty) {
             Operand::Move(place)
         } else {
             Operand::Copy(place)
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 70d5fc2d958..80d8b27336c 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -876,21 +876,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 } => {
                     self.local_decls[local].mutability = mutability;
                     self.local_decls[local].source_info.scope = self.source_scope;
-                    self.local_decls[local].local_info = if let Some(kind) = param.self_kind {
-                        Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(
-                            BindingForm::ImplicitSelf(kind),
-                        ))))
-                    } else {
-                        let binding_mode = ty::BindingMode::BindByValue(mutability);
-                        Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
-                            VarBindingForm {
+                    **self.local_decls[local].local_info.as_mut().assert_crate_local() =
+                        if let Some(kind) = param.self_kind {
+                            LocalInfo::User(BindingForm::ImplicitSelf(kind))
+                        } else {
+                            let binding_mode = ty::BindingMode::BindByValue(mutability);
+                            LocalInfo::User(BindingForm::Var(VarBindingForm {
                                 binding_mode,
                                 opt_ty_info: param.ty_span,
                                 opt_match_place: Some((None, span)),
                                 pat_span: span,
-                            },
-                        )))))
-                    };
+                            }))
+                        };
                     self.var_indices.insert(var, LocalsForNode::One(local));
                 }
                 _ => {
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index f6db329fd7c..8937b78fe34 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -18,7 +18,7 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         let trait_substs = match tcx.trait_of_item(def_id.to_def_id()) {
             Some(trait_def_id) => {
                 let trait_substs_count = tcx.generics_of(trait_def_id).count();
-                &InternalSubsts::identity_for_item(tcx, def_id.to_def_id())[..trait_substs_count]
+                &InternalSubsts::identity_for_item(tcx, def_id)[..trait_substs_count]
             }
             _ => &[],
         };
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 9086412c09a..cecb8a61aa2 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -780,7 +780,6 @@ impl<'tcx> Cx<'tcx> {
             hir::ExprKind::DropTemps(ref source) => {
                 ExprKind::Use { source: self.mirror_expr(source) }
             }
-            hir::ExprKind::Box(ref value) => ExprKind::Box { value: self.mirror_expr(value) },
             hir::ExprKind::Array(ref fields) => {
                 ExprKind::Array { fields: self.mirror_exprs(fields) }
             }
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 ff88d001351..274c2f06137 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
@@ -1,14 +1,14 @@
 use rustc_hir as hir;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::traits::Obligation;
 use rustc_middle::mir::{self, Field};
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::lint;
 use rustc_span::Span;
-use rustc_trait_selection::traits::predicate_for_trait_def;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
+use rustc_trait_selection::traits::{self, ObligationCause};
 
 use std::cell::Cell;
 
@@ -189,17 +189,15 @@ impl<'tcx> ConstToPat<'tcx> {
         // using `PartialEq::eq` in this scenario in the past.)
         let partial_eq_trait_id =
             self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span));
-        let obligation: PredicateObligation<'_> = predicate_for_trait_def(
+        let partial_eq_obligation = Obligation::new(
             self.tcx(),
+            ObligationCause::dummy(),
             self.param_env,
-            ObligationCause::misc(self.span, self.id.owner.def_id),
-            partial_eq_trait_id,
-            0,
-            [ty, ty],
+            self.tcx().mk_trait_ref(partial_eq_trait_id, [ty, ty]),
         );
-        // FIXME: should this call a `predicate_must_hold` variant instead?
 
-        let has_impl = self.infcx.predicate_may_hold(&obligation);
+        // FIXME: should this call a `predicate_must_hold` variant instead?
+        let has_impl = self.infcx.predicate_may_hold(&partial_eq_obligation);
 
         // Note: To fix rust-lang/rust#65466, we could just remove this type
         // walk hack for function pointers, and unconditionally error
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index bd12087629c..486275570bd 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -655,26 +655,20 @@ where
     ///
     /// ```text
     /// loop-block:
-    ///    can_go = cur == length_or_end
+    ///    can_go = cur == len
     ///    if can_go then succ else drop-block
     /// drop-block:
-    ///    if ptr_based {
-    ///        ptr = cur
-    ///        cur = cur.offset(1)
-    ///    } else {
-    ///        ptr = &raw mut P[cur]
-    ///        cur = cur + 1
-    ///    }
+    ///    ptr = &raw mut P[cur]
+    ///    cur = cur + 1
     ///    drop(ptr)
     /// ```
     fn drop_loop(
         &mut self,
         succ: BasicBlock,
         cur: Local,
-        length_or_end: Place<'tcx>,
+        len: Local,
         ety: Ty<'tcx>,
         unwind: Unwind,
-        ptr_based: bool,
     ) -> BasicBlock {
         let copy = |place: Place<'tcx>| Operand::Copy(place);
         let move_ = |place: Place<'tcx>| Operand::Move(place);
@@ -683,22 +677,19 @@ where
         let ptr_ty = tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut });
         let ptr = Place::from(self.new_temp(ptr_ty));
         let can_go = Place::from(self.new_temp(tcx.types.bool));
-
         let one = self.constant_usize(1);
-        let (ptr_next, cur_next) = if ptr_based {
-            (
-                Rvalue::Use(copy(cur.into())),
-                Rvalue::BinaryOp(BinOp::Offset, Box::new((move_(cur.into()), one))),
-            )
-        } else {
-            (
-                Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place, cur)),
-                Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))),
-            )
-        };
 
         let drop_block = BasicBlockData {
-            statements: vec![self.assign(ptr, ptr_next), self.assign(Place::from(cur), cur_next)],
+            statements: vec![
+                self.assign(
+                    ptr,
+                    Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place, cur)),
+                ),
+                self.assign(
+                    cur.into(),
+                    Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))),
+                ),
+            ],
             is_cleanup: unwind.is_cleanup(),
             terminator: Some(Terminator {
                 source_info: self.source_info,
@@ -711,10 +702,7 @@ where
         let loop_block = BasicBlockData {
             statements: vec![self.assign(
                 can_go,
-                Rvalue::BinaryOp(
-                    BinOp::Eq,
-                    Box::new((copy(Place::from(cur)), copy(length_or_end))),
-                ),
+                Rvalue::BinaryOp(BinOp::Eq, Box::new((copy(Place::from(cur)), copy(len.into())))),
             )],
             is_cleanup: unwind.is_cleanup(),
             terminator: Some(Terminator {
@@ -738,13 +726,6 @@ where
 
     fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option<u64>) -> BasicBlock {
         debug!("open_drop_for_array({:?}, {:?})", ety, opt_size);
-
-        // if size_of::<ety>() == 0 {
-        //     index_based_loop
-        // } else {
-        //     ptr_based_loop
-        // }
-
         let tcx = self.tcx();
 
         if let Some(size) = opt_size {
@@ -770,86 +751,36 @@ where
             }
         }
 
-        let move_ = |place: Place<'tcx>| Operand::Move(place);
-        let elem_size = Place::from(self.new_temp(tcx.types.usize));
-        let len = Place::from(self.new_temp(tcx.types.usize));
-
-        let base_block = BasicBlockData {
-            statements: vec![
-                self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)),
-                self.assign(len, Rvalue::Len(self.place)),
-            ],
-            is_cleanup: self.unwind.is_cleanup(),
-            terminator: Some(Terminator {
-                source_info: self.source_info,
-                kind: TerminatorKind::SwitchInt {
-                    discr: move_(elem_size),
-                    targets: SwitchTargets::static_if(
-                        0,
-                        self.drop_loop_pair(ety, false, len),
-                        self.drop_loop_pair(ety, true, len),
-                    ),
-                },
-            }),
-        };
-        self.elaborator.patch().new_block(base_block)
+        self.drop_loop_pair(ety)
     }
 
     /// Creates a pair of drop-loops of `place`, which drops its contents, even
-    /// in the case of 1 panic. If `ptr_based`, creates a pointer loop,
-    /// otherwise create an index loop.
-    fn drop_loop_pair(
-        &mut self,
-        ety: Ty<'tcx>,
-        ptr_based: bool,
-        length: Place<'tcx>,
-    ) -> BasicBlock {
-        debug!("drop_loop_pair({:?}, {:?})", ety, ptr_based);
+    /// in the case of 1 panic.
+    fn drop_loop_pair(&mut self, ety: Ty<'tcx>) -> BasicBlock {
+        debug!("drop_loop_pair({:?})", ety);
         let tcx = self.tcx();
-        let iter_ty = if ptr_based { tcx.mk_mut_ptr(ety) } else { tcx.types.usize };
+        let len = self.new_temp(tcx.types.usize);
+        let cur = self.new_temp(tcx.types.usize);
 
-        let cur = self.new_temp(iter_ty);
-        let length_or_end = if ptr_based { Place::from(self.new_temp(iter_ty)) } else { length };
+        let unwind =
+            self.unwind.map(|unwind| self.drop_loop(unwind, cur, len, ety, Unwind::InCleanup));
 
-        let unwind = self.unwind.map(|unwind| {
-            self.drop_loop(unwind, cur, length_or_end, ety, Unwind::InCleanup, ptr_based)
-        });
+        let loop_block = self.drop_loop(self.succ, cur, len, ety, unwind);
 
-        let loop_block = self.drop_loop(self.succ, cur, length_or_end, ety, unwind, ptr_based);
-
-        let cur = Place::from(cur);
-        let drop_block_stmts = if ptr_based {
-            let tmp_ty = tcx.mk_mut_ptr(self.place_ty(self.place));
-            let tmp = Place::from(self.new_temp(tmp_ty));
-            // tmp = &raw mut P;
-            // cur = tmp as *mut T;
-            // end = Offset(cur, len);
-            let mir_cast_kind = ty::cast::mir_cast_kind(iter_ty, tmp_ty);
-            vec![
-                self.assign(tmp, Rvalue::AddressOf(Mutability::Mut, self.place)),
-                self.assign(cur, Rvalue::Cast(mir_cast_kind, Operand::Move(tmp), iter_ty)),
-                self.assign(
-                    length_or_end,
-                    Rvalue::BinaryOp(
-                        BinOp::Offset,
-                        Box::new((Operand::Copy(cur), Operand::Move(length))),
-                    ),
-                ),
-            ]
-        } else {
-            // cur = 0 (length already pushed)
-            let zero = self.constant_usize(0);
-            vec![self.assign(cur, Rvalue::Use(zero))]
-        };
-        let drop_block = self.elaborator.patch().new_block(BasicBlockData {
-            statements: drop_block_stmts,
+        let zero = self.constant_usize(0);
+        let block = BasicBlockData {
+            statements: vec![
+                self.assign(len.into(), Rvalue::Len(self.place)),
+                self.assign(cur.into(), Rvalue::Use(zero)),
+            ],
             is_cleanup: unwind.is_cleanup(),
             terminator: Some(Terminator {
                 source_info: self.source_info,
                 kind: TerminatorKind::Goto { target: loop_block },
             }),
-        });
+        };
 
+        let drop_block = self.elaborator.patch().new_block(block);
         // FIXME(#34708): handle partially-dropped array/slice elements.
         let reset_block = self.drop_flag_reset_block(DropFlagMode::Deep, drop_block, unwind);
         self.drop_flag_test_block(reset_block, self.succ, unwind)
diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
index 536745d2cfe..3d32c586554 100644
--- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
+++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
@@ -24,7 +24,7 @@ struct ConstMutationChecker<'a, 'tcx> {
 
 impl<'tcx> ConstMutationChecker<'_, 'tcx> {
     fn is_const_item(&self, local: Local) -> Option<DefId> {
-        if let Some(box LocalInfo::ConstRef { def_id }) = self.body.local_decls[local].local_info {
+        if let LocalInfo::ConstRef { def_id } = *self.body.local_decls[local].local_info() {
             Some(def_id)
         } else {
             None
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index a8ec568eb0d..c4d058e8ecb 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -182,7 +182,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
             // If the projection root is an artificial local that we introduced when
             // desugaring `static`, give a more specific error message
             // (avoid the general "raw pointer" clause below, that would only be confusing).
-            if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
+            if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
                 if self.tcx.is_mutable_static(def_id) {
                     self.require_unsafe(
                         UnsafetyViolationKind::General,
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index de7b8c63fc8..bebd9723740 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -4,6 +4,7 @@
 use either::Right;
 
 use rustc_const_eval::const_eval::CheckAlignment;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
@@ -151,12 +152,17 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
 pub struct ConstPropMachine<'mir, 'tcx> {
     /// The virtual call stack.
     stack: Vec<Frame<'mir, 'tcx>>,
+    pub written_only_inside_own_block_locals: FxHashSet<Local>,
     pub can_const_prop: IndexVec<Local, ConstPropMode>,
 }
 
 impl ConstPropMachine<'_, '_> {
     pub fn new(can_const_prop: IndexVec<Local, ConstPropMode>) -> Self {
-        Self { stack: Vec::new(), can_const_prop }
+        Self {
+            stack: Vec::new(),
+            written_only_inside_own_block_locals: Default::default(),
+            can_const_prop,
+        }
     }
 }
 
@@ -249,7 +255,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
                     "tried to write to a local that is marked as not propagatable"
                 )
             }
-            ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => {}
+            ConstPropMode::OnlyInsideOwnBlock => {
+                ecx.machine.written_only_inside_own_block_locals.insert(local);
+            }
+            ConstPropMode::FullConstProp => {}
         }
         ecx.machine.stack[frame].locals[local].access_mut()
     }
@@ -416,6 +425,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
         ecx.frame_mut().locals[local].value =
             LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit));
+        ecx.machine.written_only_inside_own_block_locals.remove(&local);
     }
 
     /// Returns the value, if any, of evaluating `c`.
@@ -693,7 +703,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
     }
 
-    fn ensure_not_propagated(&mut self, local: Local) {
+    fn ensure_not_propagated(&self, local: Local) {
         if cfg!(debug_assertions) {
             assert!(
                 self.get_const(local.into()).is_none()
@@ -963,17 +973,31 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
         // We remove all Locals which are restricted in propagation to their containing blocks and
         // which were modified in the current block.
         // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`.
-        let can_const_prop = std::mem::take(&mut self.ecx.machine.can_const_prop);
-        for (local, &mode) in can_const_prop.iter_enumerated() {
-            match mode {
-                ConstPropMode::FullConstProp => {}
-                ConstPropMode::NoPropagation => self.ensure_not_propagated(local),
-                ConstPropMode::OnlyInsideOwnBlock => {
-                    Self::remove_const(&mut self.ecx, local);
-                    self.ensure_not_propagated(local);
+        let mut written_only_inside_own_block_locals =
+            std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals);
+
+        // This loop can get very hot for some bodies: it check each local in each bb.
+        // To avoid this quadratic behaviour, we only clear the locals that were modified inside
+        // the current block.
+        for local in written_only_inside_own_block_locals.drain() {
+            debug_assert_eq!(
+                self.ecx.machine.can_const_prop[local],
+                ConstPropMode::OnlyInsideOwnBlock
+            );
+            Self::remove_const(&mut self.ecx, local);
+        }
+        self.ecx.machine.written_only_inside_own_block_locals =
+            written_only_inside_own_block_locals;
+
+        if cfg!(debug_assertions) {
+            for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() {
+                match mode {
+                    ConstPropMode::FullConstProp => {}
+                    ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => {
+                        self.ensure_not_propagated(local);
+                    }
                 }
             }
         }
-        self.ecx.machine.can_const_prop = can_const_prop;
     }
 }
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 68e50070e56..45bd98f39d2 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -247,6 +247,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
         ecx.frame_mut().locals[local].value =
             LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit));
+        ecx.machine.written_only_inside_own_block_locals.remove(&local);
     }
 
     fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> {
@@ -484,7 +485,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         Some(())
     }
 
-    fn ensure_not_propagated(&mut self, local: Local) {
+    fn ensure_not_propagated(&self, local: Local) {
         if cfg!(debug_assertions) {
             assert!(
                 self.get_const(local.into()).is_none()
@@ -691,17 +692,31 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
         // We remove all Locals which are restricted in propagation to their containing blocks and
         // which were modified in the current block.
         // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`.
-        let can_const_prop = std::mem::take(&mut self.ecx.machine.can_const_prop);
-        for (local, &mode) in can_const_prop.iter_enumerated() {
-            match mode {
-                ConstPropMode::FullConstProp => {}
-                ConstPropMode::NoPropagation => self.ensure_not_propagated(local),
-                ConstPropMode::OnlyInsideOwnBlock => {
-                    Self::remove_const(&mut self.ecx, local);
-                    self.ensure_not_propagated(local);
+        let mut written_only_inside_own_block_locals =
+            std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals);
+
+        // This loop can get very hot for some bodies: it check each local in each bb.
+        // To avoid this quadratic behaviour, we only clear the locals that were modified inside
+        // the current block.
+        for local in written_only_inside_own_block_locals.drain() {
+            debug_assert_eq!(
+                self.ecx.machine.can_const_prop[local],
+                ConstPropMode::OnlyInsideOwnBlock
+            );
+            Self::remove_const(&mut self.ecx, local);
+        }
+        self.ecx.machine.written_only_inside_own_block_locals =
+            written_only_inside_own_block_locals;
+
+        if cfg!(debug_assertions) {
+            for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() {
+                match mode {
+                    ConstPropMode::FullConstProp => {}
+                    ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => {
+                        self.ensure_not_propagated(local);
+                    }
                 }
             }
         }
-        self.ecx.machine.can_const_prop = can_const_prop;
     }
 }
diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
index 89ca04a1582..e5c3fa5646a 100644
--- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
+++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
@@ -5,7 +5,7 @@
 //! purposes on a best-effort basis. We compute them here and store them into the crate metadata so
 //! dependent crates can use them.
 
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location, Operand, Terminator, TerminatorKind, RETURN_PLACE};
@@ -149,7 +149,10 @@ fn type_will_always_be_passed_directly(ty: Ty<'_>) -> bool {
 /// body of the function instead of just the signature. These can be useful for optimization
 /// purposes on a best-effort basis. We compute them here and store them into the crate metadata so
 /// dependent crates can use them.
-pub fn deduced_param_attrs<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [DeducedParamAttrs] {
+pub fn deduced_param_attrs<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+) -> &'tcx [DeducedParamAttrs] {
     // This computation is unfortunately rather expensive, so don't do it unless we're optimizing.
     // Also skip it in incremental mode.
     if tcx.sess.opts.optimize == OptLevel::No || tcx.sess.opts.incremental.is_some() {
@@ -182,10 +185,6 @@ pub fn deduced_param_attrs<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [Ded
         return &[];
     }
 
-    // Deduced attributes for other crates should be read from the metadata instead of via this
-    // function.
-    debug_assert!(def_id.is_local());
-
     // Grab the optimized MIR. Analyze it to determine which arguments have been mutated.
     let body: &Body<'tcx> = tcx.optimized_mir(def_id);
     let mut deduce_read_only = DeduceReadOnly::new(body.arg_count);
diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs
index 7508df92df1..b8a5b92be4a 100644
--- a/compiler/rustc_mir_transform/src/deref_separator.rs
+++ b/compiler/rustc_mir_transform/src/deref_separator.rs
@@ -40,7 +40,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> {
                     let temp = self.patcher.new_internal_with_info(
                         ty,
                         self.local_decls[p_ref.local].source_info.span,
-                        Some(Box::new(LocalInfo::DerefTemp)),
+                        LocalInfo::DerefTemp,
                     );
 
                     // We are adding current p_ref's projections to our
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 7344ec793ea..35e7efed87a 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -788,7 +788,7 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> {
 fn is_local_required(local: Local, body: &Body<'_>) -> bool {
     match body.local_kind(local) {
         LocalKind::Arg | LocalKind::ReturnPointer => true,
-        LocalKind::Var | LocalKind::Temp => false,
+        LocalKind::Temp => false,
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index e6546911a2d..c9b24adba0c 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -1,5 +1,6 @@
-use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
 use rustc_middle::mir::*;
+use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::layout;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt};
@@ -121,9 +122,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
     tainted
 }
 
-fn required_panic_strategy(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<PanicStrategy> {
-    assert_eq!(cnum, LOCAL_CRATE);
-
+fn required_panic_strategy(tcx: TyCtxt<'_>, _: LocalCrate) -> Option<PanicStrategy> {
     if tcx.is_panic_runtime(LOCAL_CRATE) {
         return Some(tcx.sess.panic_strategy());
     }
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index b7f1cdfc7f2..8a6360114dc 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -70,7 +70,7 @@ use rustc_mir_dataflow::impls::{
 };
 use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_mir_dataflow::{self, Analysis};
-use rustc_span::def_id::DefId;
+use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
@@ -924,13 +924,19 @@ fn compute_layout<'tcx>(
         debug!(?decl);
 
         let ignore_for_traits = if tcx.sess.opts.unstable_opts.drop_tracking_mir {
+            // Do not `assert_crate_local` here, as post-borrowck cleanup may have already cleared
+            // the information. This is alright, since `ignore_for_traits` is only relevant when
+            // this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer
+            // default.
             match decl.local_info {
                 // Do not include raw pointers created from accessing `static` items, as those could
                 // well be re-created by another access to the same static.
-                Some(box LocalInfo::StaticRef { is_thread_local, .. }) => !is_thread_local,
+                ClearCrossCrate::Set(box LocalInfo::StaticRef { is_thread_local, .. }) => {
+                    !is_thread_local
+                }
                 // Fake borrows are only read by fake reads, so do not have any reality in
                 // post-analysis MIR.
-                Some(box LocalInfo::FakeBorrow) => true,
+                ClearCrossCrate::Set(box LocalInfo::FakeBorrow) => true,
                 _ => false,
             }
         } else {
@@ -1380,10 +1386,9 @@ fn create_cases<'tcx>(
 #[instrument(level = "debug", skip(tcx), ret)]
 pub(crate) fn mir_generator_witnesses<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
+    def_id: LocalDefId,
 ) -> GeneratorLayout<'tcx> {
     assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir);
-    let def_id = def_id.expect_local();
 
     let (body, _) = tcx.mir_promoted(ty::WithOptConstParam::unknown(def_id));
     let body = body.borrow();
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index b2c477c84d2..3a515fe8323 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -29,9 +29,9 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::visit::Visitor as _;
 use rustc_middle::mir::{
-    traversal, AnalysisPhase, Body, ConstQualifs, Constant, LocalDecl, MirPass, MirPhase, Operand,
-    Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind,
-    TerminatorKind,
+    traversal, AnalysisPhase, Body, ClearCrossCrate, ConstQualifs, Constant, LocalDecl, MirPass,
+    MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
+    Statement, StatementKind, TerminatorKind,
 };
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
@@ -112,7 +112,6 @@ pub fn provide(providers: &mut Providers) {
         mir_keys,
         mir_const,
         mir_const_qualif: |tcx, def_id| {
-            let def_id = def_id.expect_local();
             if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
                 tcx.mir_const_qualif_const_arg(def)
             } else {
@@ -133,7 +132,6 @@ pub fn provide(providers: &mut Providers) {
         mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable,
         mir_inliner_callees: inline::cycle::mir_inliner_callees,
         promoted_mir: |tcx, def_id| {
-            let def_id = def_id.expect_local();
             if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
                 tcx.promoted_mir_of_const_arg(def)
             } else {
@@ -206,8 +204,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
     body
 }
 
-fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    let def_id = def_id.expect_local();
+fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     tcx.mir_keys(()).contains(&def_id)
 }
 
@@ -350,12 +347,11 @@ fn mir_promoted(
 }
 
 /// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
-fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> {
-    let did = def_id.expect_local();
-    if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
+fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> {
+    if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
         tcx.mir_for_ctfe_of_const_arg(def)
     } else {
-        tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(did)))
+        tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(def_id)))
     }
 }
 
@@ -532,6 +528,12 @@ fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         &[&lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops")];
 
     pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
+
+    // Clear this by anticipation. Optimizations and runtime MIR have no reason to look
+    // into this information, which is meant for borrowck diagnostics.
+    for decl in &mut body.local_decls {
+        decl.local_info = ClearCrossCrate::Clear;
+    }
 }
 
 fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -593,8 +595,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 }
 
 /// Optimize the MIR and prepare it for codegen.
-fn optimized_mir(tcx: TyCtxt<'_>, did: DefId) -> &Body<'_> {
-    let did = did.expect_local();
+fn optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &Body<'_> {
     assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None);
     tcx.arena.alloc(inner_optimized_mir(tcx, did))
 }
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index f596cc1808f..46eab1184bd 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -6,6 +6,7 @@ use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
+use rustc_target::abi::VariantIdx;
 
 pub struct LowerIntrinsics;
 
@@ -149,6 +150,35 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                             terminator.kind = TerminatorKind::Goto { target };
                         }
                     }
+                    sym::read_via_copy => {
+                        let [arg] = args.as_slice() else {
+                            span_bug!(terminator.source_info.span, "Wrong number of arguments");
+                        };
+                        let derefed_place =
+                            if let Some(place) = arg.place() && let Some(local) = place.as_local() {
+                                tcx.mk_place_deref(local.into())
+                            } else {
+                                span_bug!(terminator.source_info.span, "Only passing a local is supported");
+                            };
+                        terminator.kind = match *target {
+                            None => {
+                                // No target means this read something uninhabited,
+                                // so it must be unreachable, and we don't need to
+                                // preserve the assignment either.
+                                TerminatorKind::Unreachable
+                            }
+                            Some(target) => {
+                                block.statements.push(Statement {
+                                    source_info: terminator.source_info,
+                                    kind: StatementKind::Assign(Box::new((
+                                        *destination,
+                                        Rvalue::Use(Operand::Copy(derefed_place)),
+                                    ))),
+                                });
+                                TerminatorKind::Goto { target }
+                            }
+                        }
+                    }
                     sym::discriminant_value => {
                         if let (Some(target), Some(arg)) = (*target, args[0].place()) {
                             let arg = tcx.mk_place_deref(arg);
@@ -162,6 +192,35 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                             terminator.kind = TerminatorKind::Goto { target };
                         }
                     }
+                    sym::option_payload_ptr => {
+                        if let (Some(target), Some(arg)) = (*target, args[0].place()) {
+                            let ty::RawPtr(ty::TypeAndMut { ty: dest_ty, .. }) =
+                                destination.ty(local_decls, tcx).ty.kind()
+                            else { bug!(); };
+
+                            block.statements.push(Statement {
+                                source_info: terminator.source_info,
+                                kind: StatementKind::Assign(Box::new((
+                                    *destination,
+                                    Rvalue::AddressOf(
+                                        Mutability::Not,
+                                        arg.project_deeper(
+                                            &[
+                                                PlaceElem::Deref,
+                                                PlaceElem::Downcast(
+                                                    Some(sym::Some),
+                                                    VariantIdx::from_u32(1),
+                                                ),
+                                                PlaceElem::Field(Field::from_u32(0), *dest_ty),
+                                            ],
+                                            tcx,
+                                        ),
+                                    ),
+                                ))),
+                            });
+                            terminator.kind = TerminatorKind::Goto { target };
+                        }
+                    }
                     _ if intrinsic_name.as_str().starts_with("simd_shuffle") => {
                         validate_simd_shuffle(tcx, args, terminator.source_info.span);
                     }
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index 4291e81c78c..b6e73eaad50 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -102,7 +102,7 @@ fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option<Local> {
             mir::LocalKind::Arg => return None,
 
             mir::LocalKind::ReturnPointer => bug!("Return place was assigned to itself?"),
-            mir::LocalKind::Var | mir::LocalKind::Temp => {}
+            mir::LocalKind::Temp => {}
         }
 
         // If multiple different locals are copied to the return place. We can't pick a
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index 1becfddb23b..1f37f03cff1 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -1,7 +1,9 @@
-//! Removes assignments to ZST places.
+//! Removes operations on ZST places, and convert ZST operands to constants.
 
 use crate::MirPass;
-use rustc_middle::mir::{Body, StatementKind};
+use rustc_middle::mir::interpret::ConstValue;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 pub struct RemoveZsts;
@@ -16,38 +18,24 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts {
         if tcx.type_of(body.source.def_id()).subst_identity().is_generator() {
             return;
         }
-        let param_env = tcx.param_env(body.source.def_id());
-        let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
+        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
         let local_decls = &body.local_decls;
-        for block in basic_blocks {
-            for statement in block.statements.iter_mut() {
-                if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) =
-                    statement.kind
-                {
-                    let place_ty = place.ty(local_decls, tcx).ty;
-                    if !maybe_zst(place_ty) {
-                        continue;
-                    }
-                    let Ok(layout) = tcx.layout_of(param_env.and(place_ty)) else {
-                        continue;
-                    };
-                    if !layout.is_zst() {
-                        continue;
-                    }
-                    if tcx.consider_optimizing(|| {
-                        format!(
-                            "RemoveZsts - Place: {:?} SourceInfo: {:?}",
-                            place, statement.source_info
-                        )
-                    }) {
-                        statement.make_nop();
-                    }
-                }
-            }
+        let mut replacer = Replacer { tcx, param_env, local_decls };
+        for var_debug_info in &mut body.var_debug_info {
+            replacer.visit_var_debug_info(var_debug_info);
+        }
+        for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
+            replacer.visit_basic_block_data(bb, data);
         }
     }
 }
 
+struct Replacer<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    local_decls: &'a LocalDecls<'tcx>,
+}
+
 /// A cheap, approximate check to avoid unnecessary `layout_of` calls.
 fn maybe_zst(ty: Ty<'_>) -> bool {
     match ty.kind() {
@@ -63,3 +51,93 @@ fn maybe_zst(ty: Ty<'_>) -> bool {
         _ => false,
     }
 }
+
+impl<'tcx> Replacer<'_, 'tcx> {
+    fn known_to_be_zst(&self, ty: Ty<'tcx>) -> bool {
+        if !maybe_zst(ty) {
+            return false;
+        }
+        let Ok(layout) = self.tcx.layout_of(self.param_env.and(ty)) else {
+            return false;
+        };
+        layout.is_zst()
+    }
+
+    fn make_zst(&self, ty: Ty<'tcx>) -> Constant<'tcx> {
+        debug_assert!(self.known_to_be_zst(ty));
+        Constant {
+            span: rustc_span::DUMMY_SP,
+            user_ty: None,
+            literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
+        }
+    }
+}
+
+impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) {
+        match var_debug_info.value {
+            VarDebugInfoContents::Const(_) => {}
+            VarDebugInfoContents::Place(place) => {
+                let place_ty = place.ty(self.local_decls, self.tcx).ty;
+                if self.known_to_be_zst(place_ty) {
+                    var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(place_ty))
+                }
+            }
+            VarDebugInfoContents::Composite { ty, fragments: _ } => {
+                if self.known_to_be_zst(ty) {
+                    var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(ty))
+                }
+            }
+        }
+    }
+
+    fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
+        if let Operand::Constant(_) = operand {
+            return;
+        }
+        let op_ty = operand.ty(self.local_decls, self.tcx);
+        if self.known_to_be_zst(op_ty)
+            && self.tcx.consider_optimizing(|| {
+                format!("RemoveZsts - Operand: {:?} Location: {:?}", operand, loc)
+            })
+        {
+            *operand = Operand::Constant(Box::new(self.make_zst(op_ty)))
+        }
+    }
+
+    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, loc: Location) {
+        let place_for_ty = match statement.kind {
+            StatementKind::Assign(box (place, ref rvalue)) => {
+                rvalue.is_safe_to_remove().then_some(place)
+            }
+            StatementKind::Deinit(box place)
+            | StatementKind::SetDiscriminant { box place, variant_index: _ }
+            | StatementKind::AscribeUserType(box (place, _), _)
+            | StatementKind::Retag(_, box place)
+            | StatementKind::PlaceMention(box place)
+            | StatementKind::FakeRead(box (_, place)) => Some(place),
+            StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
+                Some(local.into())
+            }
+            StatementKind::Coverage(_)
+            | StatementKind::Intrinsic(_)
+            | StatementKind::Nop
+            | StatementKind::ConstEvalCounter => None,
+        };
+        if let Some(place_for_ty) = place_for_ty
+            && let ty = place_for_ty.ty(self.local_decls, self.tcx).ty
+            && self.known_to_be_zst(ty)
+            && self.tcx.consider_optimizing(|| {
+                format!("RemoveZsts - Place: {:?} SourceInfo: {:?}", place_for_ty, statement.source_info)
+            })
+        {
+            statement.make_nop();
+        } else {
+            self.super_statement(statement, loc);
+        }
+    }
+}
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index f529944acce..aff27e5664b 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1326,6 +1326,21 @@ fn create_mono_items_for_default_impls<'tcx>(
         return;
     }
 
+    // Unlike 'lazy' monomorphization that begins by collecting items transitively
+    // called by `main` or other global items, when eagerly monomorphizing impl
+    // items, we never actually check that the predicates of this impl are satisfied
+    // in a empty reveal-all param env (i.e. with no assumptions).
+    //
+    // Even though this impl has no substitutions, because we don't consider higher-
+    // ranked predicates such as `for<'a> &'a mut [u8]: Copy` to be trivially false,
+    // we must now check that the impl has no impossible-to-satisfy predicates.
+    if tcx.subst_and_check_impossible_predicates((
+        item.owner_id.to_def_id(),
+        &InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()),
+    )) {
+        return;
+    }
+
     let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else {
         return;
     };
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index b7c3dbcc091..63263a642ac 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -36,6 +36,8 @@ fn unused_generic_params<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: ty::InstanceDef<'tcx>,
 ) -> UnusedGenericParams {
+    assert!(instance.def_id().is_local());
+
     if !tcx.sess.opts.unstable_opts.polymorphize {
         // If polymorphization disabled, then all parameters are used.
         return UnusedGenericParams::new_all_used();
@@ -100,13 +102,6 @@ fn should_polymorphize<'tcx>(
         return false;
     }
 
-    // Polymorphization results are stored in cross-crate metadata only when there are unused
-    // parameters, so assume that non-local items must have only used parameters (else this query
-    // would not be invoked, and the cross-crate metadata used instead).
-    if !def_id.is_local() {
-        return false;
-    }
-
     // Foreign items have no bodies to analyze.
     if tcx.is_foreign_item(def_id) {
         return false;
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 296eb4d653c..8b69b3cb036 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1843,20 +1843,14 @@ impl<'a> Parser<'a> {
         &mut self,
         mk_lit_char: impl FnOnce(Symbol, Span) -> L,
     ) -> PResult<'a, L> {
-        if let token::Interpolated(inner) = &self.token.kind {
-            let expr = match inner.as_ref() {
-                token::NtExpr(expr) => Some(expr),
-                token::NtLiteral(expr) => Some(expr),
-                _ => None,
-            };
-            if let Some(expr) = expr {
-                if matches!(expr.kind, ExprKind::Err) {
-                    let mut err = errors::InvalidInterpolatedExpression { span: self.token.span }
-                        .into_diagnostic(&self.sess.span_diagnostic);
-                    err.downgrade_to_delayed_bug();
-                    return Err(err);
-                }
-            }
+        if let token::Interpolated(nt) = &self.token.kind
+            && let token::NtExpr(e) | token::NtLiteral(e) = &**nt
+            && matches!(e.kind, ExprKind::Err)
+        {
+            let mut err = errors::InvalidInterpolatedExpression { span: self.token.span }
+                .into_diagnostic(&self.sess.span_diagnostic);
+            err.downgrade_to_delayed_bug();
+            return Err(err);
         }
         let token = self.token.clone();
         let err = |self_: &Self| {
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 8a3cedfee79..1c5410c5658 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -14,6 +14,7 @@
 // We want to be able to build this crate with a stable compiler, so no
 // `#![feature]` attributes should be added.
 
+use rustc_lexer::unescape;
 pub use Alignment::*;
 pub use Count::*;
 pub use Piece::*;
@@ -234,8 +235,10 @@ pub struct Parser<'a> {
     last_opening_brace: Option<InnerSpan>,
     /// Whether the source string is comes from `println!` as opposed to `format!` or `print!`
     append_newline: bool,
-    /// Whether this formatting string is a literal or it comes from a macro.
-    pub is_literal: bool,
+    /// Whether this formatting string was written directly in the source. This controls whether we
+    /// can use spans to refer into it and give better error messages.
+    /// N.B: This does _not_ control whether implicit argument captures can be used.
+    pub is_source_literal: bool,
     /// Start position of the current line.
     cur_line_start: usize,
     /// Start and end byte offset of every line of the format string. Excludes
@@ -262,7 +265,7 @@ impl<'a> Iterator for Parser<'a> {
                     } else {
                         let arg = self.argument(lbrace_end);
                         if let Some(rbrace_pos) = self.must_consume('}') {
-                            if self.is_literal {
+                            if self.is_source_literal {
                                 let lbrace_byte_pos = self.to_span_index(pos);
                                 let rbrace_byte_pos = self.to_span_index(rbrace_pos);
 
@@ -302,7 +305,7 @@ impl<'a> Iterator for Parser<'a> {
                 _ => Some(String(self.string(pos))),
             }
         } else {
-            if self.is_literal {
+            if self.is_source_literal {
                 let span = self.span(self.cur_line_start, self.input.len());
                 if self.line_spans.last() != Some(&span) {
                     self.line_spans.push(span);
@@ -322,8 +325,8 @@ impl<'a> Parser<'a> {
         append_newline: bool,
         mode: ParseMode,
     ) -> Parser<'a> {
-        let input_string_kind = find_width_map_from_snippet(snippet, style);
-        let (width_map, is_literal) = match input_string_kind {
+        let input_string_kind = find_width_map_from_snippet(s, snippet, style);
+        let (width_map, is_source_literal) = match input_string_kind {
             InputStringKind::Literal { width_mappings } => (width_mappings, true),
             InputStringKind::NotALiteral => (Vec::new(), false),
         };
@@ -339,7 +342,7 @@ impl<'a> Parser<'a> {
             width_map,
             last_opening_brace: None,
             append_newline,
-            is_literal,
+            is_source_literal,
             cur_line_start: 0,
             line_spans: vec![],
         }
@@ -532,13 +535,13 @@ impl<'a> Parser<'a> {
                 '{' | '}' => {
                     return &self.input[start..pos];
                 }
-                '\n' if self.is_literal => {
+                '\n' if self.is_source_literal => {
                     self.line_spans.push(self.span(self.cur_line_start, pos));
                     self.cur_line_start = pos + 1;
                     self.cur.next();
                 }
                 _ => {
-                    if self.is_literal && pos == self.cur_line_start && c.is_whitespace() {
+                    if self.is_source_literal && pos == self.cur_line_start && c.is_whitespace() {
                         self.cur_line_start = pos + c.len_utf8();
                     }
                     self.cur.next();
@@ -890,6 +893,7 @@ impl<'a> Parser<'a> {
 /// written code (code snippet) and the `InternedString` that gets processed in the `Parser`
 /// in order to properly synthesise the intra-string `Span`s for error diagnostics.
 fn find_width_map_from_snippet(
+    input: &str,
     snippet: Option<string::String>,
     str_style: Option<usize>,
 ) -> InputStringKind {
@@ -902,8 +906,27 @@ fn find_width_map_from_snippet(
         return InputStringKind::Literal { width_mappings: Vec::new() };
     }
 
+    // Strip quotes.
     let snippet = &snippet[1..snippet.len() - 1];
 
+    // Macros like `println` add a newline at the end. That technically doens't make them "literals" anymore, but it's fine
+    // since we will never need to point our spans there, so we lie about it here by ignoring it.
+    // Since there might actually be newlines in the source code, we need to normalize away all trailing newlines.
+    // If we only trimmed it off the input, `format!("\n")` would cause a mismatch as here we they actually match up.
+    // Alternatively, we could just count the trailing newlines and only trim one from the input if they don't match up.
+    let input_no_nl = input.trim_end_matches('\n');
+    let Some(unescaped) = unescape_string(snippet) else {
+        return InputStringKind::NotALiteral;
+    };
+
+    let unescaped_no_nl = unescaped.trim_end_matches('\n');
+
+    if unescaped_no_nl != input_no_nl {
+        // The source string that we're pointing at isn't our input, so spans pointing at it will be incorrect.
+        // This can for example happen with proc macros that respan generated literals.
+        return InputStringKind::NotALiteral;
+    }
+
     let mut s = snippet.char_indices();
     let mut width_mappings = vec![];
     while let Some((pos, c)) = s.next() {
@@ -986,6 +1009,19 @@ fn find_width_map_from_snippet(
     InputStringKind::Literal { width_mappings }
 }
 
+fn unescape_string(string: &str) -> Option<string::String> {
+    let mut buf = string::String::new();
+    let mut ok = true;
+    unescape::unescape_literal(string, unescape::Mode::Str, &mut |_, unescaped_char| {
+        match unescaped_char {
+            Ok(c) => buf.push(c),
+            Err(_) => ok = false,
+        }
+    });
+
+    ok.then_some(buf)
+}
+
 // Assert a reasonable size for `Piece`
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Piece<'_>, 16);
diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml
index faa9c493d88..44f991f8c15 100644
--- a/compiler/rustc_passes/Cargo.toml
+++ b/compiler/rustc_passes/Cargo.toml
@@ -22,3 +22,4 @@ rustc_span = { path = "../rustc_span" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_feature = { path = "../rustc_feature" }
+rustc_trait_selection = { path = "../rustc_trait_selection" }
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 3fa78efc290..d063b51c8b8 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -720,26 +720,7 @@ passes_ignored_derived_impls =
      *[other] traits {$trait_list}, but these are
     } intentionally ignored during dead code analysis
 
-passes_proc_macro_typeerror = mismatched {$kind} signature
-    .label = found {$found}, expected type `proc_macro::TokenStream`
-    .note = {$kind}s must have a signature of `{$expected_signature}`
-
-passes_proc_macro_diff_arg_count = mismatched {$kind} signature
-    .label = found unexpected {$count ->
-      [one] argument
-     *[other] arguments
-    }
-    .note = {$kind}s must have a signature of `{$expected_signature}`
-
-passes_proc_macro_missing_args = mismatched {$kind} signature
-    .label = {$kind} must have {$expected_input_count ->
-      [one] one argument
-     *[other] two arguments
-    } of type `proc_macro::TokenStream`
-
-passes_proc_macro_invalid_abi = proc macro functions may not be `extern "{$abi}"`
-
-passes_proc_macro_unsafe = proc macro functions may not be `unsafe`
+passes_proc_macro_bad_sig = {$kind} has incorrect signature
 
 passes_skipping_const_checks = skipping const checks
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index c8d371dd084..8bed7888142 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -19,9 +19,10 @@ use rustc_hir::{
 use rustc_hir::{MethodKind, Target, Unsafety};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
+use rustc_middle::traits::ObligationCause;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
     UNUSED_ATTRIBUTES,
@@ -30,6 +31,9 @@ use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::traits::ObligationCtxt;
 use std::cell::Cell;
 use std::collections::hash_map::Entry;
 
@@ -2188,100 +2192,99 @@ impl CheckAttrVisitor<'_> {
     ///
     /// If this best effort goes wrong, it will just emit a worse error later (see #102923)
     fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
-        let expected_input_count = match kind {
-            ProcMacroKind::Attribute => 2,
-            ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1,
-        };
-
-        let expected_signature = match kind {
-            ProcMacroKind::Attribute => "fn(TokenStream, TokenStream) -> TokenStream",
-            ProcMacroKind::Derive | ProcMacroKind::FunctionLike => "fn(TokenStream) -> TokenStream",
-        };
+        if target != Target::Fn {
+            return;
+        }
 
         let tcx = self.tcx;
-        if target == Target::Fn {
-            let Some(tokenstream) = tcx.get_diagnostic_item(sym::TokenStream) else {return};
-            let tokenstream = tcx.type_of(tokenstream).subst_identity();
-
-            let id = hir_id.expect_owner();
-            let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id).unwrap();
-
-            let sig =
-                tcx.liberate_late_bound_regions(id.to_def_id(), tcx.fn_sig(id).subst_identity());
-            let sig = tcx.normalize_erasing_regions(ParamEnv::empty(), sig);
-
-            // We don't currently require that the function signature is equal to
-            // `fn(TokenStream) -> TokenStream`, but instead monomorphizes to
-            // `fn(TokenStream) -> TokenStream` after some substitution of generic arguments.
-            //
-            // Properly checking this means pulling in additional `rustc` crates, so we don't.
-            let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey };
-
-            if sig.abi != Abi::Rust {
-                tcx.sess.emit_err(errors::ProcMacroInvalidAbi {
-                    span: hir_sig.span,
-                    abi: sig.abi.name(),
-                });
-                self.abort.set(true);
-            }
+        let Some(token_stream_def_id) = tcx.get_diagnostic_item(sym::TokenStream) else { return; };
+        let Some(token_stream) = tcx.type_of(token_stream_def_id).no_bound_vars() else { return; };
 
-            if sig.unsafety == Unsafety::Unsafe {
-                tcx.sess.emit_err(errors::ProcMacroUnsafe { span: hir_sig.span });
-                self.abort.set(true);
-            }
+        let def_id = hir_id.expect_owner().def_id;
+        let param_env = ty::ParamEnv::empty();
 
-            let output = sig.output();
+        let infcx = tcx.infer_ctxt().build();
+        let ocx = ObligationCtxt::new(&infcx);
 
-            // Typecheck the output
-            if !drcx.types_may_unify(output, tokenstream) {
-                tcx.sess.emit_err(errors::ProcMacroTypeError {
-                    span: hir_sig.decl.output.span(),
-                    found: output,
-                    kind,
-                    expected_signature,
-                });
-                self.abort.set(true);
-            }
+        let span = tcx.def_span(def_id);
+        let fresh_substs = infcx.fresh_substs_for_item(span, def_id.to_def_id());
+        let sig = tcx.liberate_late_bound_regions(
+            def_id.to_def_id(),
+            tcx.fn_sig(def_id).subst(tcx, fresh_substs),
+        );
 
-            if sig.inputs().len() < expected_input_count {
-                tcx.sess.emit_err(errors::ProcMacroMissingArguments {
-                    expected_input_count,
-                    span: hir_sig.span,
-                    kind,
-                    expected_signature,
-                });
-                self.abort.set(true);
-            }
+        let mut cause = ObligationCause::misc(span, def_id);
+        let sig = ocx.normalize(&cause, param_env, sig);
 
-            // Check that the inputs are correct, if there are enough.
-            if sig.inputs().len() >= expected_input_count {
-                for (arg, input) in
-                    sig.inputs().iter().zip(hir_sig.decl.inputs).take(expected_input_count)
-                {
-                    if !drcx.types_may_unify(*arg, tokenstream) {
-                        tcx.sess.emit_err(errors::ProcMacroTypeError {
-                            span: input.span,
-                            found: *arg,
-                            kind,
-                            expected_signature,
-                        });
-                        self.abort.set(true);
+        // proc macro is not WF.
+        let errors = ocx.select_where_possible();
+        if !errors.is_empty() {
+            return;
+        }
+
+        let expected_sig = tcx.mk_fn_sig(
+            std::iter::repeat(token_stream).take(match kind {
+                ProcMacroKind::Attribute => 2,
+                ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1,
+            }),
+            token_stream,
+            false,
+            Unsafety::Normal,
+            Abi::Rust,
+        );
+
+        if let Err(terr) = ocx.eq(&cause, param_env, expected_sig, sig) {
+            let mut diag = tcx.sess.create_err(errors::ProcMacroBadSig { span, kind });
+
+            let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id);
+            if let Some(hir_sig) = hir_sig {
+                match terr {
+                    TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => {
+                        if let Some(ty) = hir_sig.decl.inputs.get(idx) {
+                            diag.set_span(ty.span);
+                            cause.span = ty.span;
+                        } else if idx == hir_sig.decl.inputs.len() {
+                            let span = hir_sig.decl.output.span();
+                            diag.set_span(span);
+                            cause.span = span;
+                        }
+                    }
+                    TypeError::ArgCount => {
+                        if let Some(ty) = hir_sig.decl.inputs.get(expected_sig.inputs().len()) {
+                            diag.set_span(ty.span);
+                            cause.span = ty.span;
+                        }
                     }
+                    TypeError::UnsafetyMismatch(_) => {
+                        // FIXME: Would be nice if we had a span here..
+                    }
+                    TypeError::AbiMismatch(_) => {
+                        // FIXME: Would be nice if we had a span here..
+                    }
+                    TypeError::VariadicMismatch(_) => {
+                        // FIXME: Would be nice if we had a span here..
+                    }
+                    _ => {}
                 }
             }
 
-            // Check that there are not too many arguments
-            let body_id = tcx.hir().body_owned_by(id.def_id);
-            let excess = tcx.hir().body(body_id).params.get(expected_input_count..);
-            if let Some(excess @ [begin @ end] | excess @ [begin, .., end]) = excess {
-                tcx.sess.emit_err(errors::ProcMacroDiffArguments {
-                    span: begin.span.to(end.span),
-                    count: excess.len(),
-                    kind,
-                    expected_signature,
-                });
-                self.abort.set(true);
-            }
+            infcx.err_ctxt().note_type_err(
+                &mut diag,
+                &cause,
+                None,
+                Some(ValuePairs::Sigs(ExpectedFound { expected: expected_sig, found: sig })),
+                terr,
+                false,
+                false,
+            );
+            diag.emit();
+            self.abort.set(true);
+        }
+
+        let errors = ocx.select_all_or_error();
+        if !errors.is_empty() {
+            infcx.err_ctxt().report_fulfillment_errors(&errors);
+            self.abort.set(true);
         }
     }
 }
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 526b829bf67..30dd3e4d016 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -104,9 +104,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
 
             // If this crate is not using stability attributes, or this function is not claiming to be a
             // stable `const fn`, that is all that is required.
-            if !tcx.features().staged_api
-                || tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable)
-            {
+            if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
                 return true;
             }
 
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index ec1e1d0054b..75ce446e6b4 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -469,9 +469,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
 
 fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     fn has_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
-        tcx.has_attr(def_id.to_def_id(), sym::lang)
+        tcx.has_attr(def_id, sym::lang)
             // Stable attribute for #[lang = "panic_impl"]
-            || tcx.has_attr(def_id.to_def_id(), sym::panic_handler)
+            || tcx.has_attr(def_id, sym::panic_handler)
     }
 
     fn has_allow_dead_code(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index aeacbaa67cb..9dd39a5c9fe 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -4,11 +4,9 @@ use hir::CRATE_HIR_ID;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_expand::base::resolve_path;
 use rustc_hir as hir;
-use rustc_hir::def_id::CrateNum;
 use rustc_hir::HirId;
-use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::LOCAL_CRATE;
+use rustc_middle::{query::LocalCrate, ty::query::Providers};
 use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
 
 use std::sync::Arc;
@@ -69,9 +67,7 @@ fn check_for_debugger_visualizer(
 }
 
 /// Traverses and collects the debugger visualizers for a specific crate.
-fn debugger_visualizers(tcx: TyCtxt<'_>, cnum: CrateNum) -> Vec<DebuggerVisualizerFile> {
-    assert_eq!(cnum, LOCAL_CRATE);
-
+fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> {
     // Initialize the collector.
     let mut debugger_visualizers = FxHashSet::default();
 
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index 110eb210df9..eb6ea673c85 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -12,9 +12,10 @@
 use rustc_ast as ast;
 use rustc_hir::diagnostic_items::DiagnosticItems;
 use rustc_hir::OwnerId;
+use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::symbol::{sym, Symbol};
 
 use crate::errors::DuplicateDiagnosticItemInCrate;
@@ -62,9 +63,7 @@ fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
 }
 
 /// Traverse and collect the diagnostic items in the current
-fn diagnostic_items(tcx: TyCtxt<'_>, cnum: CrateNum) -> DiagnosticItems {
-    assert_eq!(cnum, LOCAL_CRATE);
-
+fn diagnostic_items(tcx: TyCtxt<'_>, _: LocalCrate) -> DiagnosticItems {
     // Initialize the collector.
     let mut diagnostic_items = DiagnosticItems::default();
 
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 9f1c0b5a0b7..1b0cd5d91ab 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1546,52 +1546,11 @@ pub struct ChangeFieldsToBeOfUnitType {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_proc_macro_typeerror)]
-#[note]
-pub(crate) struct ProcMacroTypeError<'tcx> {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    pub found: Ty<'tcx>,
-    pub kind: ProcMacroKind,
-    pub expected_signature: &'static str,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_proc_macro_diff_arg_count)]
-pub(crate) struct ProcMacroDiffArguments {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    pub count: usize,
-    pub kind: ProcMacroKind,
-    pub expected_signature: &'static str,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_proc_macro_missing_args)]
-pub(crate) struct ProcMacroMissingArguments {
+#[diag(passes_proc_macro_bad_sig)]
+pub(crate) struct ProcMacroBadSig {
     #[primary_span]
-    #[label]
     pub span: Span,
-    pub expected_input_count: usize,
     pub kind: ProcMacroKind,
-    pub expected_signature: &'static str,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_proc_macro_invalid_abi)]
-pub(crate) struct ProcMacroInvalidAbi {
-    #[primary_span]
-    pub span: Span,
-    pub abi: &'static str,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_proc_macro_unsafe)]
-pub(crate) struct ProcMacroUnsafe {
-    #[primary_span]
-    pub span: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 3e0d53029ef..47e032758f2 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -300,7 +300,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         record_variants!(
             (self, e, e.kind, Id::Node(e.hir_id), hir, Expr, ExprKind),
             [
-                Box, ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type,
+                ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type,
                 DropTemps, Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index,
                 Path, AddrOf, Break, Continue, Ret, InlineAsm, Struct, Repeat, Yield, Err
             ]
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 047b9b525e8..5a1ae808e66 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -18,7 +18,7 @@ pub fn test_layout(tcx: TyCtxt<'_>) {
                 tcx.def_kind(id.owner_id),
                 DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
             ) {
-                for attr in tcx.get_attrs(id.owner_id.to_def_id(), sym::rustc_layout) {
+                for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) {
                     dump_layout_of(tcx, id.owner_id.def_id, attr);
                 }
             }
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index db9d0dcc300..a8471ce3b6f 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -146,7 +146,7 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: DefId) {
     // Don't run unused pass for #[derive()]
     let parent = tcx.local_parent(local_def_id);
     if let DefKind::Impl { .. } = tcx.def_kind(parent)
-        && tcx.has_attr(parent.to_def_id(), sym::automatically_derived)
+        && tcx.has_attr(parent, sym::automatically_derived)
     {
         return;
     }
@@ -473,7 +473,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
             | hir::ExprKind::Struct(..)
             | hir::ExprKind::Repeat(..)
             | hir::ExprKind::InlineAsm(..)
-            | hir::ExprKind::Box(..)
             | hir::ExprKind::Type(..)
             | hir::ExprKind::Err(_)
             | hir::ExprKind::Path(hir::QPath::TypeRelative(..))
@@ -1059,8 +1058,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 self.propagate_through_expr(&l, r_succ)
             }
 
-            hir::ExprKind::Box(ref e)
-            | hir::ExprKind::AddrOf(_, _, ref e)
+            hir::ExprKind::AddrOf(_, _, ref e)
             | hir::ExprKind::Cast(ref e, _)
             | hir::ExprKind::Type(ref e, _)
             | hir::ExprKind::DropTemps(ref e)
@@ -1425,7 +1423,6 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
         | hir::ExprKind::Closure { .. }
         | hir::ExprKind::Path(_)
         | hir::ExprKind::Yield(..)
-        | hir::ExprKind::Box(..)
         | hir::ExprKind::Type(..)
         | hir::ExprKind::Err(_) => {}
     }
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index c5b5cf7f5a9..c398467f03e 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -30,7 +30,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
             continue;
         }
 
-        let naked = tcx.has_attr(def_id.to_def_id(), sym::naked);
+        let naked = tcx.has_attr(def_id, sym::naked);
         if !naked {
             continue;
         }
@@ -59,7 +59,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
 
 /// Check that the function isn't inlined.
 fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
+    let attrs = tcx.get_attrs(def_id, sym::inline);
     for attr in attrs {
         tcx.sess.emit_err(CannotInlineNakedFunction { span: attr.span });
     }
@@ -179,8 +179,7 @@ enum ItemKind {
 impl<'tcx> CheckInlineAssembly<'tcx> {
     fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) {
         match expr.kind {
-            ExprKind::Box(..)
-            | ExprKind::ConstBlock(..)
+            ExprKind::ConstBlock(..)
             | ExprKind::Array(..)
             | ExprKind::Call(..)
             | ExprKind::MethodCall(..)
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index d5cc64a5402..6d0cfea00d1 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -691,14 +691,10 @@ pub(crate) fn provide(providers: &mut Providers) {
         check_mod_unstable_api_usage,
         stability_index,
         stability_implications: |tcx, _| tcx.stability().implications.clone(),
-        lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
-        lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()),
-        lookup_default_body_stability: |tcx, id| {
-            tcx.stability().local_default_body_stability(id.expect_local())
-        },
-        lookup_deprecation_entry: |tcx, id| {
-            tcx.stability().local_deprecation_entry(id.expect_local())
-        },
+        lookup_stability: |tcx, id| tcx.stability().local_stability(id),
+        lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id),
+        lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id),
+        lookup_deprecation_entry: |tcx, id| tcx.stability().local_deprecation_entry(id),
         ..*providers
     };
 }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index ef7c68c1a33..d884ebd9acc 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -132,7 +132,7 @@ where
                 projection.trait_ref_and_own_substs(tcx)
             } else {
                 // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys
-                let def_id = tcx.impl_trait_in_trait_parent(projection.def_id);
+                let def_id = tcx.impl_trait_in_trait_parent_fn(projection.def_id);
                 let trait_generics = tcx.generics_of(def_id);
                 (
                     tcx.mk_trait_ref(def_id, projection.substs.truncate_to(tcx, trait_generics)),
@@ -920,7 +920,7 @@ pub struct TestReachabilityVisitor<'tcx, 'a> {
 
 impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
     fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) {
-        if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) {
+        if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) {
             let mut error_msg = String::new();
             let span = self.tcx.def_span(def_id.to_def_id());
             if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) {
@@ -2060,8 +2060,8 @@ pub fn provide(providers: &mut Providers) {
     };
 }
 
-fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility<DefId> {
-    local_visibility(tcx, def_id.expect_local()).to_def_id()
+fn visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility<DefId> {
+    local_visibility(tcx, def_id).to_def_id()
 }
 
 fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility {
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 035bfe978f2..4cd94237061 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -20,7 +20,7 @@ extern crate rustc_middle;
 use rustc_data_structures::sync::AtomicU64;
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::{self, DepKindStruct};
-use rustc_middle::query::Key;
+use rustc_middle::query::AsLocalKey;
 use rustc_middle::ty::query::{
     query_keys, query_provided, query_provided_to_value, query_storage, query_values,
 };
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index ca3c3997df0..9bba26cc8e8 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -274,19 +274,19 @@ macro_rules! hash_result {
     };
 }
 
-macro_rules! get_provider {
-    ([][$tcx:expr, $name:ident, $key:expr]) => {{
-        $tcx.queries.local_providers.$name
+macro_rules! call_provider {
+    ([][$qcx:expr, $name:ident, $key:expr]) => {{
+        ($qcx.queries.local_providers.$name)($qcx.tcx, $key)
     }};
-    ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{
-        if $key.query_crate_is_local() {
-            $tcx.queries.local_providers.$name
+    ([(separate_provide_extern) $($rest:tt)*][$qcx:expr, $name:ident, $key:expr]) => {{
+        if let Some(key) = $key.as_local_key() {
+            ($qcx.queries.local_providers.$name)($qcx.tcx, key)
         } else {
-            $tcx.queries.extern_providers.$name
+            ($qcx.queries.extern_providers.$name)($qcx.tcx, $key)
         }
     }};
     ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
-        get_provider!([$($modifiers)*][$($args)*])
+        call_provider!([$($modifiers)*][$($args)*])
     };
 }
 
@@ -516,7 +516,7 @@ macro_rules! define_queries {
             fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value {
                 query_provided_to_value::$name(
                     qcx.tcx,
-                    get_provider!([$($modifiers)*][qcx, $name, key])(qcx.tcx, key)
+                    call_provider!([$($modifiers)*][qcx, $name, key])
                 )
             }
 
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 8a9a1238606..3dbcc4d2e8a 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -6,7 +6,6 @@ use rustc_data_structures::sharded::{self, Sharded};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
-use rustc_data_structures::OnDrop;
 use rustc_index::vec::IndexVec;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use smallvec::{smallvec, SmallVec};
@@ -54,6 +53,11 @@ impl From<DepNodeIndex> for QueryInvocationId {
     }
 }
 
+pub struct MarkFrame<'a> {
+    index: SerializedDepNodeIndex,
+    parent: Option<&'a MarkFrame<'a>>,
+}
+
 #[derive(PartialEq)]
 pub enum DepNodeColor {
     Red,
@@ -710,32 +714,26 @@ impl<K: DepKind> DepGraphData<K> {
         let prev_index = self.previous.node_to_index_opt(dep_node)?;
 
         match self.colors.get(prev_index) {
-            Some(DepNodeColor::Green(dep_node_index)) => return Some((prev_index, dep_node_index)),
-            Some(DepNodeColor::Red) => return None,
-            None => {}
+            Some(DepNodeColor::Green(dep_node_index)) => Some((prev_index, dep_node_index)),
+            Some(DepNodeColor::Red) => None,
+            None => {
+                // This DepNode and the corresponding query invocation existed
+                // in the previous compilation session too, so we can try to
+                // mark it as green by recursively marking all of its
+                // dependencies green.
+                self.try_mark_previous_green(qcx, prev_index, &dep_node, None)
+                    .map(|dep_node_index| (prev_index, dep_node_index))
+            }
         }
-
-        let backtrace = backtrace_printer(qcx.dep_context().sess(), self, prev_index);
-
-        // This DepNode and the corresponding query invocation existed
-        // in the previous compilation session too, so we can try to
-        // mark it as green by recursively marking all of its
-        // dependencies green.
-        let ret = self
-            .try_mark_previous_green(qcx, prev_index, &dep_node)
-            .map(|dep_node_index| (prev_index, dep_node_index));
-
-        // We succeeded, no backtrace.
-        backtrace.disable();
-        return ret;
     }
 
-    #[instrument(skip(self, qcx, parent_dep_node_index), level = "debug")]
+    #[instrument(skip(self, qcx, parent_dep_node_index, frame), level = "debug")]
     fn try_mark_parent_green<Qcx: QueryContext<DepKind = K>>(
         &self,
         qcx: Qcx,
         parent_dep_node_index: SerializedDepNodeIndex,
         dep_node: &DepNode<K>,
+        frame: Option<&MarkFrame<'_>>,
     ) -> Option<()> {
         let dep_dep_node_color = self.colors.get(parent_dep_node_index);
         let dep_dep_node = &self.previous.index_to_node(parent_dep_node_index);
@@ -767,7 +765,8 @@ impl<K: DepKind> DepGraphData<K> {
                 dep_dep_node, dep_dep_node.hash,
             );
 
-            let node_index = self.try_mark_previous_green(qcx, parent_dep_node_index, dep_dep_node);
+            let node_index =
+                self.try_mark_previous_green(qcx, parent_dep_node_index, dep_dep_node, frame);
 
             if node_index.is_some() {
                 debug!("managed to MARK dependency {dep_dep_node:?} as green",);
@@ -777,7 +776,7 @@ impl<K: DepKind> DepGraphData<K> {
 
         // We failed to mark it green, so we try to force the query.
         debug!("trying to force dependency {dep_dep_node:?}");
-        if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node) {
+        if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node, frame) {
             // The DepNode could not be forced.
             debug!("dependency {dep_dep_node:?} could not be forced");
             return None;
@@ -816,13 +815,16 @@ 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), level = "debug")]
+    #[instrument(skip(self, qcx, prev_dep_node_index, frame), level = "debug")]
     fn try_mark_previous_green<Qcx: QueryContext<DepKind = K>>(
         &self,
         qcx: Qcx,
         prev_dep_node_index: SerializedDepNodeIndex,
         dep_node: &DepNode<K>,
+        frame: Option<&MarkFrame<'_>>,
     ) -> Option<DepNodeIndex> {
+        let frame = MarkFrame { index: prev_dep_node_index, parent: frame };
+
         #[cfg(not(parallel_compiler))]
         {
             debug_assert!(!self.dep_node_exists(dep_node));
@@ -837,10 +839,7 @@ impl<K: DepKind> DepGraphData<K> {
         let prev_deps = self.previous.edge_targets_from(prev_dep_node_index);
 
         for &dep_dep_node_index in prev_deps {
-            let backtrace = backtrace_printer(qcx.dep_context().sess(), self, dep_dep_node_index);
-            let success = self.try_mark_parent_green(qcx, dep_dep_node_index, dep_node);
-            backtrace.disable();
-            success?;
+            self.try_mark_parent_green(qcx, dep_dep_node_index, dep_node, Some(&frame))?;
         }
 
         // If we got here without hitting a `return` that means that all
@@ -970,6 +969,7 @@ impl<K: DepKind> DepGraph<K> {
     }
 
     pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex {
+        debug_assert!(self.data.is_none());
         let index = self.virtual_dep_node_index.fetch_add(1, Relaxed);
         DepNodeIndex::from_u32(index)
     }
@@ -1414,25 +1414,25 @@ impl DepNodeColorMap {
     }
 }
 
-fn backtrace_printer<'a, K: DepKind>(
-    sess: &'a rustc_session::Session,
-    graph: &'a DepGraphData<K>,
-    node: SerializedDepNodeIndex,
-) -> OnDrop<impl Fn() + 'a> {
-    OnDrop(
-        #[inline(never)]
-        #[cold]
-        move || {
-            let node = graph.previous.index_to_node(node);
-            // Do not try to rely on DepNode's Debug implementation, since it may panic.
-            let diag = rustc_errors::Diagnostic::new(
-                rustc_errors::Level::FailureNote,
-                &format!(
-                    "encountered while trying to mark dependency green: {:?}({})",
-                    node.kind, node.hash
-                ),
-            );
-            sess.diagnostic().force_print_diagnostic(diag);
-        },
-    )
+#[inline(never)]
+#[cold]
+pub(crate) fn print_markframe_trace<K: DepKind>(
+    graph: &DepGraph<K>,
+    frame: Option<&MarkFrame<'_>>,
+) {
+    let data = graph.data.as_ref().unwrap();
+
+    eprintln!("there was a panic while trying to force a dep node");
+    eprintln!("try_mark_green dep node stack:");
+
+    let mut i = 0;
+    let mut current = frame;
+    while let Some(frame) = current {
+        let node = data.previous.index_to_node(frame.index);
+        eprintln!("#{i} {:?}", node);
+        current = frame.parent;
+        i += 1;
+    }
+
+    eprintln!("end of try_mark_green dep node stack");
 }
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index 5a7b9ae2ab4..40e7131987f 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -17,8 +17,10 @@ use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_serialize::{opaque::FileEncoder, Encodable};
 use rustc_session::Session;
 
-use std::fmt;
 use std::hash::Hash;
+use std::{fmt, panic};
+
+use self::graph::{print_markframe_trace, MarkFrame};
 
 pub trait DepContext: Copy {
     type DepKind: self::DepKind;
@@ -53,11 +55,23 @@ pub trait DepContext: Copy {
     }
 
     /// Try to force a dep node to execute and see if it's green.
-    #[instrument(skip(self), level = "debug")]
-    fn try_force_from_dep_node(self, dep_node: DepNode<Self::DepKind>) -> bool {
+    #[inline]
+    #[instrument(skip(self, frame), level = "debug")]
+    fn try_force_from_dep_node(
+        self,
+        dep_node: DepNode<Self::DepKind>,
+        frame: Option<&MarkFrame<'_>>,
+    ) -> bool {
         let cb = self.dep_kind_info(dep_node.kind);
         if let Some(f) = cb.force_from_dep_node {
-            f(self, dep_node);
+            if let Err(value) = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+                f(self, dep_node);
+            })) {
+                if !value.is::<rustc_errors::FatalErrorMarker>() {
+                    print_markframe_trace(self.dep_graph(), frame);
+                }
+                panic::resume_unwind(value)
+            }
             true
         } else {
             false
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 005512cf53e..ba2f859ff0f 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -379,7 +379,11 @@ where
 
     match JobOwner::<'_, Q::Key, Qcx::DepKind>::try_start(&qcx, state, state_lock, span, key) {
         TryGetJob::NotYetStarted(job) => {
-            let (result, dep_node_index) = execute_job(query, qcx, key.clone(), dep_node, job.id);
+            let (result, dep_node_index) = match qcx.dep_context().dep_graph().data() {
+                None => execute_job_non_incr(query, qcx, key, job.id),
+                Some(data) => execute_job_incr(query, qcx, data, key, dep_node, job.id),
+            };
+
             let cache = query.query_cache(qcx);
             if query.feedable() {
                 // We should not compute queries that also got a value via feeding.
@@ -413,48 +417,55 @@ where
     }
 }
 
+// Fast path for when incr. comp. is off.
 #[inline(always)]
-fn execute_job<Q, Qcx>(
+fn execute_job_non_incr<Q, Qcx>(
     query: Q,
     qcx: Qcx,
     key: Q::Key,
-    mut dep_node_opt: Option<DepNode<Qcx::DepKind>>,
     job_id: QueryJobId,
 ) -> (Q::Value, DepNodeIndex)
 where
     Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
 {
-    let dep_graph = qcx.dep_context().dep_graph();
-    let dep_graph_data = match dep_graph.data() {
-        // Fast path for when incr. comp. is off.
-        None => {
-            // Fingerprint the key, just to assert that it doesn't
-            // have anything we don't consider hashable
-            if cfg!(debug_assertions) {
-                let _ = key.to_fingerprint(*qcx.dep_context());
-            }
+    debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled());
 
-            let prof_timer = qcx.dep_context().profiler().query_provider();
-            let result =
-                qcx.start_query(job_id, query.depth_limit(), None, || query.compute(qcx, key));
-            let dep_node_index = dep_graph.next_virtual_depnode_index();
-            prof_timer.finish_with_query_invocation_id(dep_node_index.into());
-
-            // Similarly, fingerprint the result to assert that
-            // it doesn't have anything not considered hashable.
-            if cfg!(debug_assertions) && let Some(hash_result) = query.hash_result()
-            {
-                qcx.dep_context().with_stable_hashing_context(|mut hcx| {
-                    hash_result(&mut hcx, &result);
-                });
-            }
+    // Fingerprint the key, just to assert that it doesn't
+    // have anything we don't consider hashable
+    if cfg!(debug_assertions) {
+        let _ = key.to_fingerprint(*qcx.dep_context());
+    }
 
-            return (result, dep_node_index);
-        }
-        Some(data) => data,
-    };
+    let prof_timer = qcx.dep_context().profiler().query_provider();
+    let result = qcx.start_query(job_id, query.depth_limit(), None, || query.compute(qcx, key));
+    let dep_node_index = qcx.dep_context().dep_graph().next_virtual_depnode_index();
+    prof_timer.finish_with_query_invocation_id(dep_node_index.into());
+
+    // Similarly, fingerprint the result to assert that
+    // it doesn't have anything not considered hashable.
+    if cfg!(debug_assertions) && let Some(hash_result) = query.hash_result() {
+        qcx.dep_context().with_stable_hashing_context(|mut hcx| {
+            hash_result(&mut hcx, &result);
+        });
+    }
 
+    (result, dep_node_index)
+}
+
+#[inline(always)]
+fn execute_job_incr<Q, Qcx>(
+    query: Q,
+    qcx: Qcx,
+    dep_graph_data: &DepGraphData<Qcx::DepKind>,
+    key: Q::Key,
+    mut dep_node_opt: Option<DepNode<Qcx::DepKind>>,
+    job_id: QueryJobId,
+) -> (Q::Value, DepNodeIndex)
+where
+    Q: QueryConfig<Qcx>,
+    Qcx: QueryContext,
+{
     if !query.anon() && !query.eval_always() {
         // `to_dep_node` is expensive for some `DepKind`s.
         let dep_node =
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 5d40c6e4e48..4d4bc1be349 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -85,20 +85,28 @@ impl<'a> std::fmt::Debug for ImportKind<'a> {
             Single {
                 ref source,
                 ref target,
+                ref source_bindings,
+                ref target_bindings,
                 ref type_ns_only,
                 ref nested,
                 ref id,
-                // Ignore the following to avoid an infinite loop while printing.
-                source_bindings: _,
-                target_bindings: _,
             } => f
                 .debug_struct("Single")
                 .field("source", source)
                 .field("target", target)
+                // Ignore the nested bindings to avoid an infinite loop while printing.
+                .field(
+                    "source_bindings",
+                    &source_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))),
+                )
+                .field(
+                    "target_bindings",
+                    &target_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))),
+                )
                 .field("type_ns_only", type_ns_only)
                 .field("nested", nested)
                 .field("id", id)
-                .finish_non_exhaustive(),
+                .finish(),
             Glob { ref is_prelude, ref max_vis, ref id } => f
                 .debug_struct("Glob")
                 .field("is_prelude", is_prelude)
@@ -415,13 +423,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     /// Resolves all imports for the crate. This method performs the fixed-
     /// point iteration.
     pub(crate) fn resolve_imports(&mut self) {
-        let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1;
-        while self.indeterminate_imports.len() < prev_num_indeterminates {
-            prev_num_indeterminates = self.indeterminate_imports.len();
+        let mut prev_indeterminate_count = usize::MAX;
+        let mut indeterminate_count = self.indeterminate_imports.len() * 3;
+        while indeterminate_count < prev_indeterminate_count {
+            prev_indeterminate_count = indeterminate_count;
+            indeterminate_count = 0;
             for import in mem::take(&mut self.indeterminate_imports) {
-                match self.resolve_import(&import) {
-                    true => self.determined_imports.push(import),
-                    false => self.indeterminate_imports.push(import),
+                let import_indeterminate_count = self.resolve_import(&import);
+                indeterminate_count += import_indeterminate_count;
+                match import_indeterminate_count {
+                    0 => self.determined_imports.push(import),
+                    _ => self.indeterminate_imports.push(import),
                 }
             }
         }
@@ -573,9 +585,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         diag.emit();
     }
 
-    /// Attempts to resolve the given import, returning true if its resolution is determined.
-    /// If successful, the resolved bindings are written into the module.
-    fn resolve_import(&mut self, import: &'a Import<'a>) -> bool {
+    /// Attempts to resolve the given import, returning:
+    /// - `0` means its resolution is determined.
+    /// - Other values mean that indeterminate exists under certain namespaces.
+    ///
+    /// Meanwhile, if resolve successful, the resolved bindings are written
+    /// into the module.
+    fn resolve_import(&mut self, import: &'a Import<'a>) -> usize {
         debug!(
             "(resolving import for module) resolving import `{}::...` in `{}`",
             Segment::names_to_string(&import.module_path),
@@ -593,8 +609,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
             match path_res {
                 PathResult::Module(module) => module,
-                PathResult::Indeterminate => return false,
-                PathResult::NonModule(..) | PathResult::Failed { .. } => return true,
+                PathResult::Indeterminate => return 3,
+                PathResult::NonModule(..) | PathResult::Failed { .. } => return 0,
             }
         };
 
@@ -610,12 +626,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             } => (source, target, source_bindings, target_bindings, type_ns_only),
             ImportKind::Glob { .. } => {
                 self.resolve_glob_import(import);
-                return true;
+                return 0;
             }
             _ => unreachable!(),
         };
 
-        let mut indeterminate = false;
+        let mut indeterminate_count = 0;
         self.per_ns(|this, ns| {
             if !type_ns_only || ns == TypeNS {
                 if let Err(Undetermined) = source_bindings[ns].get() {
@@ -638,7 +654,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
                 let parent = import.parent_scope.module;
                 match source_bindings[ns].get() {
-                    Err(Undetermined) => indeterminate = true,
+                    Err(Undetermined) => indeterminate_count += 1,
                     // Don't update the resolution, because it was never added.
                     Err(Determined) if target.name == kw::Underscore => {}
                     Ok(binding) if binding.is_importable() => {
@@ -662,7 +678,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
         });
 
-        !indeterminate
+        indeterminate_count
     }
 
     /// Performs final import resolution, consistency checks and error reporting.
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index eff10e5af9f..1afd8851ce0 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1478,8 +1478,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                                     } else {
                                         LifetimeUseSet::Many
                                     }),
-                                    LifetimeRibKind::Generics { .. } => None,
-                                    LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => {
+                                    LifetimeRibKind::Generics { .. }
+                                    | LifetimeRibKind::ConstGeneric => None,
+                                    LifetimeRibKind::AnonConst => {
                                         span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind)
                                     }
                                 })
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 805c2ff280d..df7681dc426 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1289,25 +1289,41 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
                     let span = find_span(&source, err);
                     err.span_label(self.r.def_span(def_id), &format!("`{path_str}` defined here"));
-                    let (tail, descr, applicability) = match source {
-                        PathSource::Pat | PathSource::TupleStruct(..) => {
-                            ("", "pattern", Applicability::MachineApplicable)
-                        }
-                        _ => (": val", "literal", Applicability::HasPlaceholders),
-                    };
 
+                    let (tail, descr, applicability, old_fields) = match source {
+                        PathSource::Pat => ("", "pattern", Applicability::MachineApplicable, None),
+                        PathSource::TupleStruct(_, args) => (
+                            "",
+                            "pattern",
+                            Applicability::MachineApplicable,
+                            Some(
+                                args.iter()
+                                    .map(|a| self.r.tcx.sess.source_map().span_to_snippet(*a).ok())
+                                    .collect::<Vec<Option<String>>>(),
+                            ),
+                        ),
+                        _ => (": val", "literal", Applicability::HasPlaceholders, None),
+                    };
                     let field_ids = self.r.field_def_ids(def_id);
                     let (fields, applicability) = match field_ids {
-                        Some(field_ids) => (
-                            field_ids
-                                .iter()
-                                .map(|&field_id| {
-                                    format!("{}{tail}", self.r.tcx.item_name(field_id))
-                                })
-                                .collect::<Vec<String>>()
-                                .join(", "),
-                            applicability,
-                        ),
+                        Some(field_ids) => {
+                            let fields = field_ids.iter().map(|&id| self.r.tcx.item_name(id));
+
+                            let fields = if let Some(old_fields) = old_fields {
+                                fields
+                                    .enumerate()
+                                    .map(|(idx, new)| (new, old_fields.get(idx)))
+                                    .map(|(new, old)| {
+                                        let new = new.to_ident_string();
+                                        if let Some(Some(old)) = old && new != *old { format!("{}: {}", new, old) } else { new }
+                                    })
+                                    .collect::<Vec<String>>()
+                            } else {
+                                fields.map(|f| format!("{f}{tail}")).collect::<Vec<String>>()
+                            };
+
+                            (fields.join(", "), applicability)
+                        }
                         None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
                     };
                     let pad = match field_ids {
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index d8db86c5f62..9e337dde995 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -24,5 +24,9 @@ termize = "0.1.1"
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
 
-[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["libloaderapi"] }
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
+features = [
+    "Win32_Foundation",
+    "Win32_System_LibraryLoader",
+]
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index 868ffdf0f1d..a262c06d91f 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -67,12 +67,11 @@ pub enum LinkagePreference {
 #[derive(Debug, Encodable, Decodable, HashStable_Generic)]
 pub struct NativeLib {
     pub kind: NativeLibKind,
-    pub name: Option<Symbol>,
+    pub name: Symbol,
     /// If packed_bundled_libs enabled, actual filename of library is stored.
     pub filename: Option<Symbol>,
     pub cfg: Option<ast::MetaItem>,
     pub foreign_module: Option<DefId>,
-    pub wasm_import_module: Option<Symbol>,
     pub verbatim: Option<bool>,
     pub dll_imports: Vec<DllImport>,
 }
@@ -81,6 +80,10 @@ impl NativeLib {
     pub fn has_modifiers(&self) -> bool {
         self.verbatim.is_some() || self.kind.has_modifiers()
     }
+
+    pub fn wasm_import_module(&self) -> Option<Symbol> {
+        if self.kind == NativeLibKind::WasmImportModule { Some(self.name) } else { None }
+    }
 }
 
 /// Different ways that the PE Format can decorate a symbol name.
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index f1fbf38217d..e734599cbfc 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -87,35 +87,38 @@ fn current_dll_path() -> Result<PathBuf, String> {
     use std::ffi::OsString;
     use std::io;
     use std::os::windows::prelude::*;
-    use std::ptr;
 
-    use winapi::um::libloaderapi::{
-        GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+    use windows::{
+        core::PCWSTR,
+        Win32::Foundation::HINSTANCE,
+        Win32::System::LibraryLoader::{
+            GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+        },
     };
 
+    let mut module = HINSTANCE::default();
     unsafe {
-        let mut module = ptr::null_mut();
-        let r = GetModuleHandleExW(
+        GetModuleHandleExW(
             GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
-            current_dll_path as usize as *mut _,
+            PCWSTR(current_dll_path as *mut u16),
             &mut module,
-        );
-        if r == 0 {
-            return Err(format!("GetModuleHandleExW failed: {}", io::Error::last_os_error()));
-        }
-        let mut space = Vec::with_capacity(1024);
-        let r = GetModuleFileNameW(module, space.as_mut_ptr(), space.capacity() as u32);
-        if r == 0 {
-            return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error()));
-        }
-        let r = r as usize;
-        if r >= space.capacity() {
-            return Err(format!("our buffer was too small? {}", io::Error::last_os_error()));
-        }
-        space.set_len(r);
-        let os = OsString::from_wide(&space);
-        Ok(PathBuf::from(os))
+        )
     }
+    .ok()
+    .map_err(|e| e.to_string())?;
+
+    let mut filename = vec![0; 1024];
+    let n = unsafe { GetModuleFileNameW(module, &mut filename) } as usize;
+    if n == 0 {
+        return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error()));
+    }
+    if n >= filename.capacity() {
+        return Err(format!("our buffer was too small? {}", io::Error::last_os_error()));
+    }
+
+    filename.truncate(n);
+
+    Ok(OsString::from_wide(&filename).into())
 }
 
 pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index b466a3fcdee..0548379dc2f 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1422,6 +1422,9 @@ options! {
     fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
         (default: no)"),
+    flatten_format_args: bool = (false, parse_bool, [TRACKED],
+        "flatten nested format_args!() and literals into a simplified format_args!() call \
+        (default: no)"),
     force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
         "force all crates to be `rustc_private` unstable (default: no)"),
     fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index b996d36a318..3b3d4ca5d6b 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -37,6 +37,10 @@ pub enum NativeLibKind {
     /// Argument which is passed to linker, relative order with libraries and other arguments
     /// is preserved
     LinkArg,
+
+    /// Module imported from WebAssembly
+    WasmImportModule,
+
     /// The library kind wasn't specified, `Dylib` is currently used as a default.
     Unspecified,
 }
@@ -50,7 +54,10 @@ impl NativeLibKind {
             NativeLibKind::Dylib { as_needed } | NativeLibKind::Framework { as_needed } => {
                 as_needed.is_some()
             }
-            NativeLibKind::RawDylib | NativeLibKind::Unspecified | NativeLibKind::LinkArg => false,
+            NativeLibKind::RawDylib
+            | NativeLibKind::Unspecified
+            | NativeLibKind::LinkArg
+            | NativeLibKind::WasmImportModule => false,
         }
     }
 
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 9f22e9776d4..d727aba6de5 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -880,7 +880,7 @@ impl Span {
     pub fn fresh_expansion(self, expn_id: LocalExpnId) -> Span {
         HygieneData::with(|data| {
             self.with_ctxt(data.apply_mark(
-                SyntaxContext::root(),
+                self.ctxt(),
                 expn_id.to_expn_id(),
                 Transparency::Transparent,
             ))
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index a1cb810a429..ee895f53eba 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -448,25 +448,36 @@ impl SourceMap {
         sp: Span,
         filename_display_pref: FileNameDisplayPreference,
     ) -> String {
-        if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
-            return "no-location".to_string();
-        }
+        let (source_file, lo_line, lo_col, hi_line, hi_col) = self.span_to_location_info(sp);
+
+        let file_name = match source_file {
+            Some(sf) => sf.name.display(filename_display_pref).to_string(),
+            None => return "no-location".to_string(),
+        };
 
-        let lo = self.lookup_char_pos(sp.lo());
-        let hi = self.lookup_char_pos(sp.hi());
         format!(
-            "{}:{}:{}{}",
-            lo.file.name.display(filename_display_pref),
-            lo.line,
-            lo.col.to_usize() + 1,
+            "{file_name}:{lo_line}:{lo_col}{}",
             if let FileNameDisplayPreference::Short = filename_display_pref {
                 String::new()
             } else {
-                format!(": {}:{}", hi.line, hi.col.to_usize() + 1)
+                format!(": {hi_line}:{hi_col}")
             }
         )
     }
 
+    pub fn span_to_location_info(
+        &self,
+        sp: Span,
+    ) -> (Option<Lrc<SourceFile>>, usize, usize, usize, usize) {
+        if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
+            return (None, 0, 0, 0, 0);
+        }
+
+        let lo = self.lookup_char_pos(sp.lo());
+        let hi = self.lookup_char_pos(sp.hi());
+        (Some(lo.file), lo.line, lo.col.to_usize() + 1, hi.line, hi.col.to_usize() + 1)
+    }
+
     /// Format the span location suitable for embedding in build artifacts
     pub fn span_to_embeddable_string(&self, sp: Span) -> String {
         self.span_to_string(sp, FileNameDisplayPreference::Remapped)
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index bf27bd6c5ad..4a1abdf6318 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -792,7 +792,6 @@ symbols! {
         i64,
         i8,
         ident,
-        identity_future,
         if_let,
         if_let_guard,
         if_while_or_patterns,
@@ -985,6 +984,7 @@ symbols! {
         never_type_fallback,
         new,
         new_binary,
+        new_const,
         new_debug,
         new_display,
         new_lower_exp,
@@ -1044,6 +1044,7 @@ symbols! {
         optin_builtin_traits,
         option,
         option_env,
+        option_payload_ptr,
         options,
         or,
         or_patterns,
@@ -1154,6 +1155,7 @@ symbols! {
         read_enum_variant_arg,
         read_struct,
         read_struct_field,
+        read_via_copy,
         readonly,
         realloc,
         reason,
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index c6899f8f244..b4d5b7f3621 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -53,7 +53,7 @@ impl SymbolNamesTest<'_> {
         // The formatting of `tag({})` is chosen so that tests can elect
         // to test the entirety of the string, if they choose, or else just
         // some subset.
-        for attr in tcx.get_attrs(def_id.to_def_id(), SYMBOL_NAME) {
+        for attr in tcx.get_attrs(def_id, SYMBOL_NAME) {
             let def_id = def_id.to_def_id();
             let instance = Instance::new(
                 def_id,
@@ -79,7 +79,7 @@ impl SymbolNamesTest<'_> {
             }
         }
 
-        for attr in tcx.get_attrs(def_id.to_def_id(), DEF_PATH) {
+        for attr in tcx.get_attrs(def_id, DEF_PATH) {
             tcx.sess.emit_err(TestOutput {
                 span: attr.span,
                 kind: Kind::DefPath,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 0d86a3032a6..f3304e91429 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1115,6 +1115,7 @@ supported_targets! {
     // FIXME(#106649): Remove aarch64-fuchsia in favor of aarch64-unknown-fuchsia
     ("aarch64-fuchsia", aarch64_fuchsia),
     ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia),
+    ("riscv64gc-unknown-fuchsia", riscv64gc_unknown_fuchsia),
     // FIXME(#106649): Remove x86_64-fuchsia in favor of x86_64-unknown-fuchsia
     ("x86_64-fuchsia", x86_64_fuchsia),
     ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia),
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_fuchsia.rs
new file mode 100644
index 00000000000..0585ed76fe8
--- /dev/null
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_fuchsia.rs
@@ -0,0 +1,19 @@
+use crate::spec::{CodeModel, SanitizerSet, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "riscv64-unknown-fuchsia".into(),
+        pointer_width: 64,
+        data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
+        arch: "riscv64".into(),
+        options: TargetOptions {
+            code_model: Some(CodeModel::Medium),
+            cpu: "generic-rv64".into(),
+            features: "+m,+a,+f,+d,+c".into(),
+            llvm_abiname: "lp64d".into(),
+            max_atomic_width: Some(64),
+            supported_sanitizers: SanitizerSet::SHADOWCALLSTACK,
+            ..super::fuchsia_base::opts()
+        },
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 9b47c7299bb..911cc0b88c4 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -8,26 +8,16 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryRes
 use rustc_middle::traits::query::Fallible;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_middle::ty::{GenericArg, ToPredicate};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::DUMMY_SP;
 
 use std::fmt::Debug;
 
 pub use rustc_infer::infer::*;
 
 pub trait InferCtxtExt<'tcx> {
-    fn type_is_copy_modulo_regions(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        ty: Ty<'tcx>,
-        span: Span,
-    ) -> bool;
+    fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool;
 
-    fn type_is_sized_modulo_regions(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        ty: Ty<'tcx>,
-        span: Span,
-    ) -> bool;
+    fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool;
 
     /// Check whether a `ty` implements given trait(trait_def_id).
     /// The inputs are:
@@ -46,13 +36,9 @@ pub trait InferCtxtExt<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
     ) -> traits::EvaluationResult;
 }
+
 impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
-    fn type_is_copy_modulo_regions(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        ty: Ty<'tcx>,
-        span: Span,
-    ) -> bool {
+    fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
         let ty = self.resolve_vars_if_possible(ty);
 
         if !(param_env, ty).needs_infer() {
@@ -65,17 +51,12 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         // rightly refuses to work with inference variables, but
         // moves_by_default has a cache, which we want to use in other
         // cases.
-        traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
+        traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id)
     }
 
-    fn type_is_sized_modulo_regions(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        ty: Ty<'tcx>,
-        span: Span,
-    ) -> bool {
+    fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
         let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
-        traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span)
+        traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item)
     }
 
     #[instrument(level = "debug", skip(self, params), ret)]
diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index 891ea0cdebe..76cde1a6692 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -224,7 +224,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         if goal.predicate.self_ty().is_ty_var() {
             return vec![Candidate {
                 source: CandidateSource::BuiltinImpl,
-                result: self.make_canonical_response(Certainty::AMBIGUOUS).unwrap(),
+                result: self
+                    .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+                    .unwrap(),
             }];
         }
 
@@ -261,8 +263,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else {
             return
         };
-        self.probe(|this| {
-            let normalized_ty = this.next_ty_infer();
+
+        self.probe(|ecx| {
+            let normalized_ty = ecx.next_ty_infer();
             let normalizes_to_goal = goal.with(
                 tcx,
                 ty::Binder::dummy(ty::ProjectionPredicate {
@@ -270,28 +273,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                     term: normalized_ty.into(),
                 }),
             );
-            let normalization_certainty = match this.evaluate_goal(normalizes_to_goal) {
-                Ok((_, certainty)) => certainty,
-                Err(NoSolution) => return,
-            };
-            let normalized_ty = this.resolve_vars_if_possible(normalized_ty);
-
-            // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate.
-            // This doesn't work as long as we use `CandidateSource` in winnowing.
-            let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
-            let normalized_candidates = this.assemble_and_evaluate_candidates(goal);
-            for mut normalized_candidate in normalized_candidates {
-                normalized_candidate.result =
-                    normalized_candidate.result.unchecked_map(|mut response| {
-                        // FIXME: This currently hides overflow in the normalization step of the self type
-                        // which is probably wrong. Maybe `unify_and` should actually keep overflow as
-                        // we treat it as non-fatal anyways.
-                        response.certainty = response.certainty.unify_and(normalization_certainty);
-                        response
-                    });
-                candidates.push(normalized_candidate);
+            ecx.add_goal(normalizes_to_goal);
+            if let Ok(_) = ecx.try_evaluate_added_goals() {
+                let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty);
+
+                // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate.
+                // This doesn't work as long as we use `CandidateSource` in winnowing.
+                let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
+                candidates.extend(ecx.assemble_and_evaluate_candidates(goal));
             }
-        })
+        });
     }
 
     fn assemble_impl_candidates<G: GoalKind<'tcx>>(
@@ -516,7 +507,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                 } else {
                     Certainty::AMBIGUOUS
                 };
-                return self.make_canonical_response(certainty);
+                return self.evaluate_added_goals_and_make_canonical_response(certainty);
             }
         }
 
@@ -538,14 +529,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         }
     }
 
-    fn discard_reservation_impl(&self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> {
+    fn discard_reservation_impl(&mut self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> {
         if let CandidateSource::Impl(def_id) = candidate.source {
             if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) {
                 debug!("Selected reservation impl");
                 // We assemble all candidates inside of a probe so by
                 // making a new canonical response here our result will
                 // have no constraints.
-                candidate.result = self.make_canonical_response(Certainty::AMBIGUOUS).unwrap();
+                candidate.result = self
+                    .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+                    .unwrap();
             }
         }
 
diff --git a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs
index 8c3be8da16b..9d45e78ebab 100644
--- a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs
@@ -48,7 +48,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     /// - `external_constraints`: additional constraints which aren't expressable
     ///   using simple unification of inference variables.
     #[instrument(level = "debug", skip(self))]
-    pub(super) fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> {
+    pub(super) fn evaluate_added_goals_and_make_canonical_response(
+        &mut self,
+        certainty: Certainty,
+    ) -> QueryResult<'tcx> {
+        let goals_certainty = self.try_evaluate_added_goals()?;
+        let certainty = certainty.unify_and(goals_certainty);
+
         let external_constraints = self.compute_external_query_constraints()?;
 
         let response = Response { var_values: self.var_values, external_constraints, certainty };
@@ -209,7 +215,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             // FIXME: To deal with #105787 I also expect us to emit nested obligations here at
             // some point. We can figure out how to deal with this once we actually have
             // an ICE.
-            let nested_goals = self.eq(param_env, orig, response)?;
+            let nested_goals = self.eq_and_get_goals(param_env, orig, response)?;
             assert!(nested_goals.is_empty(), "{nested_goals:?}");
         }
 
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index ca438a103cf..95412922357 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -2,8 +2,11 @@ use rustc_hir::def_id::DefId;
 use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
+use rustc_infer::infer::{
+    DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt,
+};
 use rustc_infer::traits::query::NoSolution;
+use rustc_infer::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::ty::{
@@ -13,8 +16,8 @@ use rustc_middle::ty::{
 use rustc_span::DUMMY_SP;
 use std::ops::ControlFlow;
 
-use super::search_graph::SearchGraph;
-use super::Goal;
+use super::search_graph::{self, OverflowHandler};
+use super::{search_graph::SearchGraph, Goal};
 
 pub struct EvalCtxt<'a, 'tcx> {
     // FIXME: should be private.
@@ -33,14 +36,305 @@ pub struct EvalCtxt<'a, 'tcx> {
 
     pub(super) search_graph: &'a mut SearchGraph<'tcx>,
 
-    /// This field is used by a debug assertion in [`EvalCtxt::evaluate_goal`],
-    /// see the comment in that method for more details.
-    pub in_projection_eq_hack: bool,
+    pub(super) nested_goals: NestedGoals<'tcx>,
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub(super) enum IsNormalizesToHack {
+    Yes,
+    No,
+}
+
+#[derive(Debug, Clone)]
+pub(super) struct NestedGoals<'tcx> {
+    pub(super) normalizes_to_hack_goal: Option<Goal<'tcx, ty::ProjectionPredicate<'tcx>>>,
+    pub(super) goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
+}
+
+impl NestedGoals<'_> {
+    pub(super) fn new() -> Self {
+        Self { normalizes_to_hack_goal: None, goals: Vec::new() }
+    }
+
+    pub(super) fn is_empty(&self) -> bool {
+        self.normalizes_to_hack_goal.is_none() && self.goals.is_empty()
+    }
+}
+
+pub trait InferCtxtEvalExt<'tcx> {
+    /// Evaluates a goal from **outside** of the trait solver.
+    ///
+    /// Using this while inside of the solver is wrong as it uses a new
+    /// search graph which would break cycle detection.
+    fn evaluate_root_goal(
+        &self,
+        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+    ) -> Result<(bool, Certainty), NoSolution>;
+}
+
+impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
+    #[instrument(level = "debug", skip(self))]
+    fn evaluate_root_goal(
+        &self,
+        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+    ) -> Result<(bool, Certainty), NoSolution> {
+        let mut search_graph = search_graph::SearchGraph::new(self.tcx);
+
+        let mut ecx = EvalCtxt {
+            search_graph: &mut search_graph,
+            infcx: self,
+            // Only relevant when canonicalizing the response.
+            max_input_universe: ty::UniverseIndex::ROOT,
+            var_values: CanonicalVarValues::dummy(),
+            nested_goals: NestedGoals::new(),
+        };
+        let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal);
+
+        assert!(
+            ecx.nested_goals.is_empty(),
+            "root `EvalCtxt` should not have any goals added to it"
+        );
+
+        assert!(search_graph.is_empty());
+        result
+    }
+}
+
+impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
+    /// The entry point of the solver.
+    ///
+    /// This function deals with (coinductive) cycles, overflow, and caching
+    /// and then calls [`EvalCtxt::compute_goal`] which contains the actual
+    /// logic of the solver.
+    ///
+    /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal]
+    /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're
+    /// outside of it.
+    #[instrument(level = "debug", skip(tcx, search_graph), ret)]
+    fn evaluate_canonical_goal(
+        tcx: TyCtxt<'tcx>,
+        search_graph: &'a mut search_graph::SearchGraph<'tcx>,
+        canonical_goal: CanonicalGoal<'tcx>,
+    ) -> QueryResult<'tcx> {
+        // Deal with overflow, caching, and coinduction.
+        //
+        // The actual solver logic happens in `ecx.compute_goal`.
+        search_graph.with_new_goal(tcx, canonical_goal, |search_graph| {
+            let (ref infcx, goal, var_values) =
+                tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
+            let mut ecx = EvalCtxt {
+                infcx,
+                var_values,
+                max_input_universe: canonical_goal.max_universe,
+                search_graph,
+                nested_goals: NestedGoals::new(),
+            };
+            ecx.compute_goal(goal)
+        })
+    }
+
+    /// Recursively evaluates `goal`, returning whether any inference vars have
+    /// been constrained and the certainty of the result.
+    fn evaluate_goal(
+        &mut self,
+        is_normalizes_to_hack: IsNormalizesToHack,
+        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+    ) -> Result<(bool, Certainty), NoSolution> {
+        let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
+        let canonical_response =
+            EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
+
+        let has_changed = !canonical_response.value.var_values.is_identity();
+        let certainty = self.instantiate_and_apply_query_response(
+            goal.param_env,
+            orig_values,
+            canonical_response,
+        )?;
+
+        // Check that rerunning this query with its inference constraints applied
+        // doesn't result in new inference constraints and has the same result.
+        //
+        // If we have projection goals like `<T as Trait>::Assoc == u32` we recursively
+        // call `exists<U> <T as Trait>::Assoc == U` to enable better caching. This goal
+        // could constrain `U` to `u32` which would cause this check to result in a
+        // solver cycle.
+        if cfg!(debug_assertions)
+            && has_changed
+            && is_normalizes_to_hack == IsNormalizesToHack::No
+            && !self.search_graph.in_cycle()
+        {
+            debug!("rerunning goal to check result is stable");
+            let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
+            let canonical_response =
+                EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
+            if !canonical_response.value.var_values.is_identity() {
+                bug!("unstable result: {goal:?} {canonical_goal:?} {canonical_response:?}");
+            }
+            assert_eq!(certainty, canonical_response.value.certainty);
+        }
+
+        Ok((has_changed, certainty))
+    }
+
+    fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
+        let Goal { param_env, predicate } = goal;
+        let kind = predicate.kind();
+        if let Some(kind) = kind.no_bound_vars() {
+            match kind {
+                ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => {
+                    self.compute_trait_goal(Goal { param_env, predicate })
+                }
+                ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => {
+                    self.compute_projection_goal(Goal { param_env, predicate })
+                }
+                ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => {
+                    self.compute_type_outlives_goal(Goal { param_env, predicate })
+                }
+                ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => {
+                    self.compute_region_outlives_goal(Goal { param_env, predicate })
+                }
+                ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
+                    self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
+                }
+                ty::PredicateKind::Subtype(predicate) => {
+                    self.compute_subtype_goal(Goal { param_env, predicate })
+                }
+                ty::PredicateKind::Coerce(predicate) => {
+                    self.compute_coerce_goal(Goal { param_env, predicate })
+                }
+                ty::PredicateKind::ClosureKind(def_id, substs, kind) => self
+                    .compute_closure_kind_goal(Goal {
+                        param_env,
+                        predicate: (def_id, substs, kind),
+                    }),
+                ty::PredicateKind::ObjectSafe(trait_def_id) => {
+                    self.compute_object_safe_goal(trait_def_id)
+                }
+                ty::PredicateKind::WellFormed(arg) => {
+                    self.compute_well_formed_goal(Goal { param_env, predicate: arg })
+                }
+                ty::PredicateKind::Ambiguous => {
+                    self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+                }
+                // FIXME: implement these predicates :)
+                ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => {
+                    self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                }
+                ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+                    bug!("TypeWellFormedFromEnv is only used for Chalk")
+                }
+                ty::PredicateKind::AliasEq(lhs, rhs) => {
+                    self.compute_alias_eq_goal(Goal { param_env, predicate: (lhs, rhs) })
+                }
+            }
+        } else {
+            let kind = self.infcx.instantiate_binder_with_placeholders(kind);
+            let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
+            self.add_goal(goal);
+            self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        }
+    }
+
+    // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning
+    // the certainty of all the goals.
+    #[instrument(level = "debug", skip(self))]
+    pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolution> {
+        let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new());
+        let mut new_goals = NestedGoals::new();
+
+        let response = self.repeat_while_none(
+            |_| Ok(Certainty::Maybe(MaybeCause::Overflow)),
+            |this| {
+                let mut has_changed = Err(Certainty::Yes);
+
+                if let Some(goal) = goals.normalizes_to_hack_goal.take() {
+                    let (_, certainty) = match this.evaluate_goal(
+                        IsNormalizesToHack::Yes,
+                        goal.with(this.tcx(), ty::Binder::dummy(goal.predicate)),
+                    ) {
+                        Ok(r) => r,
+                        Err(NoSolution) => return Some(Err(NoSolution)),
+                    };
+
+                    if goal.predicate.projection_ty
+                        != this.resolve_vars_if_possible(goal.predicate.projection_ty)
+                    {
+                        has_changed = Ok(())
+                    }
+
+                    match certainty {
+                        Certainty::Yes => {}
+                        Certainty::Maybe(_) => {
+                            let goal = this.resolve_vars_if_possible(goal);
+
+                            // The rhs of this `normalizes-to` must always be an unconstrained infer var as it is
+                            // the hack used by `normalizes-to` to ensure that every `normalizes-to` behaves the same
+                            // regardless of the rhs.
+                            //
+                            // However it is important not to unconditionally replace the rhs with a new infer var
+                            // as otherwise we may replace the original unconstrained infer var with a new infer var
+                            // and never propagate any constraints on the new var back to the original var.
+                            let term = this
+                                .term_is_fully_unconstrained(goal)
+                                .then_some(goal.predicate.term)
+                                .unwrap_or_else(|| {
+                                    this.next_term_infer_of_kind(goal.predicate.term)
+                                });
+                            let projection_pred = ty::ProjectionPredicate {
+                                term,
+                                projection_ty: goal.predicate.projection_ty,
+                            };
+                            new_goals.normalizes_to_hack_goal =
+                                Some(goal.with(this.tcx(), projection_pred));
+
+                            has_changed = has_changed.map_err(|c| c.unify_and(certainty));
+                        }
+                    }
+                }
+
+                for nested_goal in goals.goals.drain(..) {
+                    let (changed, certainty) =
+                        match this.evaluate_goal(IsNormalizesToHack::No, nested_goal) {
+                            Ok(result) => result,
+                            Err(NoSolution) => return Some(Err(NoSolution)),
+                        };
+
+                    if changed {
+                        has_changed = Ok(());
+                    }
+
+                    match certainty {
+                        Certainty::Yes => {}
+                        Certainty::Maybe(_) => {
+                            new_goals.goals.push(nested_goal);
+                            has_changed = has_changed.map_err(|c| c.unify_and(certainty));
+                        }
+                    }
+                }
+
+                core::mem::swap(&mut new_goals, &mut goals);
+                match has_changed {
+                    Ok(()) => None,
+                    Err(certainty) => Some(Ok(certainty)),
+                }
+            },
+        );
+
+        self.nested_goals = goals;
+        response
+    }
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
     pub(super) fn probe<T>(&mut self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T {
-        self.infcx.probe(|_| f(self))
+        let mut ecx = EvalCtxt {
+            infcx: self.infcx,
+            var_values: self.var_values,
+            max_input_universe: self.max_input_universe,
+            search_graph: self.search_graph,
+            nested_goals: self.nested_goals.clone(),
+        };
+        self.infcx.probe(|_| f(&mut ecx))
     }
 
     pub(super) fn tcx(&self) -> TyCtxt<'tcx> {
@@ -61,6 +355,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         )
     }
 
+    /// Returns a ty infer or a const infer depending on whether `kind` is a `Ty` or `Const`.
+    /// If `kind` is an integer inference variable this will still return a ty infer var.
+    pub(super) fn next_term_infer_of_kind(&self, kind: ty::Term<'tcx>) -> ty::Term<'tcx> {
+        match kind.unpack() {
+            ty::TermKind::Ty(_) => self.next_ty_infer().into(),
+            ty::TermKind::Const(ct) => self.next_const_infer(ct.ty()).into(),
+        }
+    }
+
     /// Is the projection predicate is of the form `exists<T> <Ty as Trait>::Assoc = T`.
     ///
     /// This is the case if the `term` is an inference variable in the innermost universe
@@ -137,6 +440,30 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
     #[instrument(level = "debug", skip(self, param_env), ret)]
     pub(super) fn eq<T: ToTrace<'tcx>>(
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        lhs: T,
+        rhs: T,
+    ) -> Result<(), NoSolution> {
+        self.infcx
+            .at(&ObligationCause::dummy(), param_env)
+            .eq(DefineOpaqueTypes::No, lhs, rhs)
+            .map(|InferOk { value: (), obligations }| {
+                self.add_goals(obligations.into_iter().map(|o| o.into()));
+            })
+            .map_err(|e| {
+                debug!(?e, "failed to equate");
+                NoSolution
+            })
+    }
+
+    /// Equates two values returning the nested goals without adding them
+    /// to the nested goals of the `EvalCtxt`.
+    ///
+    /// If possible, try using `eq` instead which automatically handles nested
+    /// goals correctly.
+    #[instrument(level = "debug", skip(self, param_env), ret)]
+    pub(super) fn eq_and_get_goals<T: ToTrace<'tcx>>(
         &self,
         param_env: ty::ParamEnv<'tcx>,
         lhs: T,
@@ -144,7 +471,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
         self.infcx
             .at(&ObligationCause::dummy(), param_env)
-            .eq(lhs, rhs)
+            .eq(DefineOpaqueTypes::No, lhs, rhs)
             .map(|InferOk { value: (), obligations }| {
                 obligations.into_iter().map(|o| o.into()).collect()
             })
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 55d361b1204..606c2eaa510 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -15,23 +15,19 @@
 
 // FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented.
 
-use std::mem;
-
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
-use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::traits::solve::{
     CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData,
-    Goal, MaybeCause, QueryResult, Response,
+    Goal, QueryResult, Response,
 };
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{
     CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
 };
-use rustc_span::DUMMY_SP;
 
-use crate::solve::search_graph::OverflowHandler;
 use crate::traits::ObligationCause;
 
 mod assembly;
@@ -42,7 +38,7 @@ mod project_goals;
 mod search_graph;
 mod trait_goals;
 
-pub use eval_ctxt::EvalCtxt;
+pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt};
 pub use fulfill::FulfillmentCtxt;
 
 trait CanonicalResponseExt {
@@ -57,180 +53,18 @@ impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> {
     }
 }
 
-pub trait InferCtxtEvalExt<'tcx> {
-    /// Evaluates a goal from **outside** of the trait solver.
-    ///
-    /// Using this while inside of the solver is wrong as it uses a new
-    /// search graph which would break cycle detection.
-    fn evaluate_root_goal(
-        &self,
-        goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    ) -> Result<(bool, Certainty), NoSolution>;
-}
-
-impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
-    fn evaluate_root_goal(
-        &self,
-        goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    ) -> Result<(bool, Certainty), NoSolution> {
-        let mut search_graph = search_graph::SearchGraph::new(self.tcx);
-
-        let result = EvalCtxt {
-            search_graph: &mut search_graph,
-            infcx: self,
-            // Only relevant when canonicalizing the response.
-            max_input_universe: ty::UniverseIndex::ROOT,
-            var_values: CanonicalVarValues::dummy(),
-            in_projection_eq_hack: false,
-        }
-        .evaluate_goal(goal);
-
-        assert!(search_graph.is_empty());
-        result
-    }
-}
-
 impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
-    /// The entry point of the solver.
-    ///
-    /// This function deals with (coinductive) cycles, overflow, and caching
-    /// and then calls [`EvalCtxt::compute_goal`] which contains the actual
-    /// logic of the solver.
-    ///
-    /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal]
-    /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're
-    /// outside of it.
-    #[instrument(level = "debug", skip(tcx, search_graph), ret)]
-    fn evaluate_canonical_goal(
-        tcx: TyCtxt<'tcx>,
-        search_graph: &'a mut search_graph::SearchGraph<'tcx>,
-        canonical_goal: CanonicalGoal<'tcx>,
-    ) -> QueryResult<'tcx> {
-        // Deal with overflow, caching, and coinduction.
-        //
-        // The actual solver logic happens in `ecx.compute_goal`.
-        search_graph.with_new_goal(tcx, canonical_goal, |search_graph| {
-            let (ref infcx, goal, var_values) =
-                tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
-            let mut ecx = EvalCtxt {
-                infcx,
-                var_values,
-                max_input_universe: canonical_goal.max_universe,
-                search_graph,
-                in_projection_eq_hack: false,
-            };
-            ecx.compute_goal(goal)
-        })
-    }
-
-    /// Recursively evaluates `goal`, returning whether any inference vars have
-    /// been constrained and the certainty of the result.
-    fn evaluate_goal(
-        &mut self,
-        goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    ) -> Result<(bool, Certainty), NoSolution> {
-        let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
-        let canonical_response =
-            EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
-
-        let has_changed = !canonical_response.value.var_values.is_identity();
-        let certainty = self.instantiate_and_apply_query_response(
-            goal.param_env,
-            orig_values,
-            canonical_response,
-        )?;
-
-        // Check that rerunning this query with its inference constraints applied
-        // doesn't result in new inference constraints and has the same result.
-        //
-        // If we have projection goals like `<T as Trait>::Assoc == u32` we recursively
-        // call `exists<U> <T as Trait>::Assoc == U` to enable better caching. This goal
-        // could constrain `U` to `u32` which would cause this check to result in a
-        // solver cycle.
-        if cfg!(debug_assertions)
-            && has_changed
-            && !self.in_projection_eq_hack
-            && !self.search_graph.in_cycle()
-            && false
-        {
-            let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
-            let canonical_response =
-                EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
-            if !canonical_response.value.var_values.is_identity() {
-                bug!("unstable result: {goal:?} {canonical_goal:?} {canonical_response:?}");
-            }
-            assert_eq!(certainty, canonical_response.value.certainty);
-        }
-
-        Ok((has_changed, certainty))
-    }
-
-    fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
-        let Goal { param_env, predicate } = goal;
-        let kind = predicate.kind();
-        if let Some(kind) = kind.no_bound_vars() {
-            match kind {
-                ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => {
-                    self.compute_trait_goal(Goal { param_env, predicate })
-                }
-                ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => {
-                    self.compute_projection_goal(Goal { param_env, predicate })
-                }
-                ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => {
-                    self.compute_type_outlives_goal(Goal { param_env, predicate })
-                }
-                ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => {
-                    self.compute_region_outlives_goal(Goal { param_env, predicate })
-                }
-                ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
-                    self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
-                }
-                ty::PredicateKind::Subtype(predicate) => {
-                    self.compute_subtype_goal(Goal { param_env, predicate })
-                }
-                ty::PredicateKind::Coerce(predicate) => {
-                    self.compute_coerce_goal(Goal { param_env, predicate })
-                }
-                ty::PredicateKind::ClosureKind(def_id, substs, kind) => self
-                    .compute_closure_kind_goal(Goal {
-                        param_env,
-                        predicate: (def_id, substs, kind),
-                    }),
-                ty::PredicateKind::ObjectSafe(trait_def_id) => {
-                    self.compute_object_safe_goal(trait_def_id)
-                }
-                ty::PredicateKind::WellFormed(arg) => {
-                    self.compute_well_formed_goal(Goal { param_env, predicate: arg })
-                }
-                ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::AMBIGUOUS),
-                // FIXME: implement these predicates :)
-                ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => {
-                    self.make_canonical_response(Certainty::Yes)
-                }
-                ty::PredicateKind::TypeWellFormedFromEnv(..) => {
-                    bug!("TypeWellFormedFromEnv is only used for Chalk")
-                }
-                ty::PredicateKind::AliasEq(lhs, rhs) => {
-                    self.compute_alias_eq_goal(Goal { param_env, predicate: (lhs, rhs) })
-                }
-            }
-        } else {
-            let kind = self.infcx.instantiate_binder_with_placeholders(kind);
-            let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
-            let (_, certainty) = self.evaluate_goal(goal)?;
-            self.make_canonical_response(certainty)
-        }
-    }
-
+    #[instrument(level = "debug", skip(self))]
     fn compute_type_outlives_goal(
         &mut self,
         goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>,
     ) -> QueryResult<'tcx> {
         let ty::OutlivesPredicate(ty, lt) = goal.predicate;
         self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
-        self.make_canonical_response(Certainty::Yes)
+        self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn compute_region_outlives_goal(
         &mut self,
         goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>,
@@ -239,9 +73,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             &ObligationCause::dummy(),
             ty::Binder::dummy(goal.predicate),
         );
-        self.make_canonical_response(Certainty::Yes)
+        self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn compute_coerce_goal(
         &mut self,
         goal: Goal<'tcx, CoercePredicate<'tcx>>,
@@ -256,6 +91,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         })
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn compute_subtype_goal(
         &mut self,
         goal: Goal<'tcx, SubtypePredicate<'tcx>>,
@@ -263,18 +99,18 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() {
             // FIXME: Do we want to register a subtype relation between these vars?
             // That won't actually reflect in the query response, so it seems moot.
-            self.make_canonical_response(Certainty::AMBIGUOUS)
+            self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
         } else {
             let InferOk { value: (), obligations } = self
                 .infcx
                 .at(&ObligationCause::dummy(), goal.param_env)
-                .sub(goal.predicate.a, goal.predicate.b)?;
-            self.evaluate_all_and_make_canonical_response(
-                obligations.into_iter().map(|pred| pred.into()).collect(),
-            )
+                .sub(DefineOpaqueTypes::No, goal.predicate.a, goal.predicate.b)?;
+            self.add_goals(obligations.into_iter().map(|pred| pred.into()));
+            self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn compute_closure_kind_goal(
         &mut self,
         goal: Goal<'tcx, (DefId, ty::SubstsRef<'tcx>, ty::ClosureKind)>,
@@ -283,23 +119,25 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         let found_kind = substs.as_closure().kind_ty().to_opt_closure_kind();
 
         let Some(found_kind) = found_kind else {
-            return self.make_canonical_response(Certainty::AMBIGUOUS);
+            return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
         };
         if found_kind.extends(expected_kind) {
-            self.make_canonical_response(Certainty::Yes)
+            self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         } else {
             Err(NoSolution)
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> {
         if self.tcx().check_is_object_safe(trait_def_id) {
-            self.make_canonical_response(Certainty::Yes)
+            self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         } else {
             Err(NoSolution)
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn compute_well_formed_goal(
         &mut self,
         goal: Goal<'tcx, ty::GenericArg<'tcx>>,
@@ -309,10 +147,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             goal.param_env,
             goal.predicate,
         ) {
-            Some(obligations) => self.evaluate_all_and_make_canonical_response(
-                obligations.into_iter().map(|o| o.into()).collect(),
-            ),
-            None => self.make_canonical_response(Certainty::AMBIGUOUS),
+            Some(obligations) => {
+                self.add_goals(obligations.into_iter().map(|o| o.into()));
+                self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+            }
+            None => self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS),
         }
     }
 
@@ -326,14 +165,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| {
             debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
             let r = ecx.probe(|ecx| {
-                let (_, certainty) = ecx.evaluate_goal(goal.with(
+                ecx.add_goal(goal.with(
                     tcx,
                     ty::Binder::dummy(ty::ProjectionPredicate {
                         projection_ty: alias,
                         term: other,
                     }),
-                ))?;
-                ecx.make_canonical_response(certainty)
+                ));
+                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             });
             debug!("evaluate_normalizes_to(..) -> {:?}", r);
             r
@@ -360,10 +199,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
                 // Evaluate all 3 potential candidates for the alias' being equal
                 candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1));
                 candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0));
-                candidates.push(self.probe(|this| {
+                candidates.push(self.probe(|ecx| {
                     debug!("compute_alias_eq_goal: alias defids are equal, equating substs");
-                    let nested_goals = this.eq(goal.param_env, alias_lhs, alias_rhs)?;
-                    this.evaluate_all_and_make_canonical_response(nested_goals)
+                    ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 }));
 
                 debug!(?candidates);
@@ -379,62 +218,31 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>,
     ) -> QueryResult<'tcx> {
         let (ct, ty) = goal.predicate;
-        let nested_goals = self.eq(goal.param_env, ct.ty(), ty)?;
-        self.evaluate_all_and_make_canonical_response(nested_goals)
+        self.eq(goal.param_env, ct.ty(), ty)?;
+        self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
-    // Recursively evaluates a list of goals to completion, returning the certainty
-    // of all of the goals.
-    fn evaluate_all(
-        &mut self,
-        mut goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
-    ) -> Result<Certainty, NoSolution> {
-        let mut new_goals = Vec::new();
-        self.repeat_while_none(
-            |_| Ok(Certainty::Maybe(MaybeCause::Overflow)),
-            |this| {
-                let mut has_changed = Err(Certainty::Yes);
-                for goal in goals.drain(..) {
-                    let (changed, certainty) = match this.evaluate_goal(goal) {
-                        Ok(result) => result,
-                        Err(NoSolution) => return Some(Err(NoSolution)),
-                    };
-
-                    if changed {
-                        has_changed = Ok(());
-                    }
-
-                    match certainty {
-                        Certainty::Yes => {}
-                        Certainty::Maybe(_) => {
-                            new_goals.push(goal);
-                            has_changed = has_changed.map_err(|c| c.unify_and(certainty));
-                        }
-                    }
-                }
-
-                match has_changed {
-                    Ok(()) => {
-                        mem::swap(&mut new_goals, &mut goals);
-                        None
-                    }
-                    Err(certainty) => Some(Ok(certainty)),
-                }
-            },
-        )
+    #[instrument(level = "debug", skip(self))]
+    fn set_normalizes_to_hack_goal(&mut self, goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>) {
+        assert!(
+            self.nested_goals.normalizes_to_hack_goal.is_none(),
+            "attempted to set the projection eq hack goal when one already exists"
+        );
+        self.nested_goals.normalizes_to_hack_goal = Some(goal);
     }
 
-    // Recursively evaluates a list of goals to completion, making a query response.
-    //
-    // This is just a convenient way of calling [`EvalCtxt::evaluate_all`],
-    // then [`EvalCtxt::make_canonical_response`].
-    fn evaluate_all_and_make_canonical_response(
-        &mut self,
-        goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
-    ) -> QueryResult<'tcx> {
-        self.evaluate_all(goals).and_then(|certainty| self.make_canonical_response(certainty))
+    #[instrument(level = "debug", skip(self))]
+    fn add_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
+        self.nested_goals.goals.push(goal);
+    }
+
+    #[instrument(level = "debug", skip(self, goals))]
+    fn add_goals(&mut self, goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>) {
+        let current_len = self.nested_goals.goals.len();
+        self.nested_goals.goals.extend(goals);
+        debug!("added_goals={:?}", &self.nested_goals.goals[current_len..]);
     }
 
     fn try_merge_responses(
@@ -466,7 +274,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         });
         // FIXME(-Ztrait-solver=next): We should take the intersection of the constraints on all the
         // responses and use that for the constraints of this ambiguous response.
-        let response = self.make_canonical_response(certainty);
+        let response = self.evaluate_added_goals_and_make_canonical_response(certainty);
         if let Ok(response) = &response {
             assert!(response.has_no_inference_or_external_constraints());
         }
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index dbb8e722c8f..93d77c39f95 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -20,6 +20,7 @@ use rustc_span::{sym, DUMMY_SP};
 use std::iter;
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
+    #[instrument(level = "debug", skip(self), ret)]
     pub(super) fn compute_projection_goal(
         &mut self,
         goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
@@ -36,53 +37,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             self.merge_candidates_and_discard_reservation_impls(candidates)
         } else {
             let predicate = goal.predicate;
-            let unconstrained_rhs = match predicate.term.unpack() {
-                ty::TermKind::Ty(_) => self.next_ty_infer().into(),
-                ty::TermKind::Const(ct) => self.next_const_infer(ct.ty()).into(),
-            };
-            let unconstrained_predicate = ty::Clause::Projection(ProjectionPredicate {
+            let unconstrained_rhs = self.next_term_infer_of_kind(predicate.term);
+            let unconstrained_predicate = ProjectionPredicate {
                 projection_ty: goal.predicate.projection_ty,
                 term: unconstrained_rhs,
-            });
-            let (_has_changed, normalize_certainty) = self.in_projection_eq_hack(|this| {
-                this.evaluate_goal(goal.with(this.tcx(), unconstrained_predicate))
-            })?;
-
-            let nested_eq_goals = self.eq(goal.param_env, unconstrained_rhs, predicate.term)?;
-            let eval_certainty = self.evaluate_all(nested_eq_goals)?;
-            self.make_canonical_response(normalize_certainty.unify_and(eval_certainty))
-        }
-    }
-
-    /// This sets a flag used by a debug assert in [`EvalCtxt::evaluate_goal`],
-    /// see the comment in that method for more details.
-    fn in_projection_eq_hack<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
-        self.in_projection_eq_hack = true;
-        let result = f(self);
-        self.in_projection_eq_hack = false;
-        result
-    }
-
-    /// After normalizing the projection to `normalized_alias` with the given
-    /// `normalization_certainty`, constrain the inference variable `term` to it
-    /// and return a query response.
-    fn eq_term_and_make_canonical_response(
-        &mut self,
-        goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
-        normalization_certainty: Certainty,
-        normalized_alias: impl Into<ty::Term<'tcx>>,
-    ) -> QueryResult<'tcx> {
-        // The term of our goal should be fully unconstrained, so this should never fail.
-        //
-        // It can however be ambiguous when the `normalized_alias` contains a projection.
-        let nested_goals = self
-            .eq(goal.param_env, goal.predicate.term, normalized_alias.into())
-            .expect("failed to unify with unconstrained term");
-
-        let unify_certainty =
-            self.evaluate_all(nested_goals).expect("failed to unify with unconstrained term");
+            };
 
-        self.make_canonical_response(normalization_certainty.unify_and(unify_certainty))
+            self.set_normalizes_to_hack_goal(goal.with(self.tcx(), unconstrained_predicate));
+            self.try_evaluate_added_goals()?;
+            self.eq(goal.param_env, unconstrained_rhs, predicate.term)?;
+            self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        }
     }
 }
 
@@ -111,19 +76,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
             ecx.probe(|ecx| {
                 let assumption_projection_pred =
                     ecx.instantiate_binder_with_infer(poly_projection_pred);
-                let mut nested_goals = ecx.eq(
+                ecx.eq(
                     goal.param_env,
                     goal.predicate.projection_ty,
                     assumption_projection_pred.projection_ty,
                 )?;
-                nested_goals.extend(requirements);
-                let subst_certainty = ecx.evaluate_all(nested_goals)?;
-
-                ecx.eq_term_and_make_canonical_response(
-                    goal,
-                    subst_certainty,
-                    assumption_projection_pred.term,
-                )
+                ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?;
+                ecx.add_goals(requirements);
+                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             })
         } else {
             Err(NoSolution)
@@ -139,21 +99,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
             && poly_projection_pred.projection_def_id() == goal.predicate.def_id()
         {
             ecx.probe(|ecx| {
+                let tcx = ecx.tcx();
+
                 let assumption_projection_pred =
                     ecx.instantiate_binder_with_infer(poly_projection_pred);
-                let mut nested_goals = ecx.eq(
+                ecx.eq(
                     goal.param_env,
                     goal.predicate.projection_ty,
                     assumption_projection_pred.projection_ty,
                 )?;
 
-                let tcx = ecx.tcx();
                 let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
                     bug!("expected object type in `consider_object_bound_candidate`");
                 };
-                nested_goals.extend(
+                ecx.add_goals(
                     structural_traits::predicates_for_object_candidate(
-                        ecx,
+                        &ecx,
                         goal.param_env,
                         goal.predicate.projection_ty.trait_ref(tcx),
                         bounds,
@@ -161,14 +122,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                     .into_iter()
                     .map(|pred| goal.with(tcx, pred)),
                 );
-
-                let subst_certainty = ecx.evaluate_all(nested_goals)?;
-
-                ecx.eq_term_and_make_canonical_response(
-                    goal,
-                    subst_certainty,
-                    assumption_projection_pred.term,
-                )
+                ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?;
+                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             })
         } else {
             Err(NoSolution)
@@ -195,16 +150,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
             let impl_substs = ecx.fresh_substs_for_item(impl_def_id);
             let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
 
-            let mut nested_goals = ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
+            ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
+
             let where_clause_bounds = tcx
                 .predicates_of(impl_def_id)
                 .instantiate(tcx, impl_substs)
                 .predicates
                 .into_iter()
                 .map(|pred| goal.with(tcx, pred));
-
-            nested_goals.extend(where_clause_bounds);
-            let match_impl_certainty = ecx.evaluate_all(nested_goals)?;
+            ecx.add_goals(where_clause_bounds);
 
             // In case the associated item is hidden due to specialization, we have to
             // return ambiguity this would otherwise be incomplete, resulting in
@@ -216,7 +170,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                 goal.predicate.def_id(),
                 impl_def_id
             )? else {
-                return ecx.make_canonical_response(match_impl_certainty.unify_and(Certainty::AMBIGUOUS));
+                return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
             };
 
             if !assoc_def.item.defaultness(tcx).has_value() {
@@ -263,7 +217,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                 ty.map_bound(|ty| ty.into())
             };
 
-            ecx.eq_term_and_make_canonical_response(goal, match_impl_certainty, term.subst(tcx, substs))
+            ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs))?;
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
 
@@ -308,14 +263,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         goal_kind: ty::ClosureKind,
     ) -> QueryResult<'tcx> {
         let tcx = ecx.tcx();
-        let Some(tupled_inputs_and_output) =
-        structural_traits::extract_tupled_inputs_and_output_from_callable(
-            tcx,
-            goal.predicate.self_ty(),
-            goal_kind,
-        )? else {
-        return ecx.make_canonical_response(Certainty::AMBIGUOUS);
-    };
+        let tupled_inputs_and_output =
+            match structural_traits::extract_tupled_inputs_and_output_from_callable(
+                tcx,
+                goal.predicate.self_ty(),
+                goal_kind,
+            )? {
+                Some(tupled_inputs_and_output) => tupled_inputs_and_output,
+                None => {
+                    return ecx
+                        .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
+                }
+            };
         let output_is_sized_pred = tupled_inputs_and_output
             .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
 
@@ -380,13 +339,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                         [ty::GenericArg::from(goal.predicate.self_ty())],
                     ));
 
-                    let (_, is_sized_certainty) =
-                        ecx.evaluate_goal(goal.with(tcx, sized_predicate))?;
-                    return ecx.eq_term_and_make_canonical_response(
-                        goal,
-                        is_sized_certainty,
-                        tcx.types.unit,
-                    );
+                    ecx.add_goal(goal.with(tcx, sized_predicate));
+                    ecx.eq(goal.param_env, goal.predicate.term, tcx.types.unit.into())?;
+                    return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
                 }
 
                 ty::Adt(def, substs) if def.is_struct() => {
@@ -394,12 +349,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                         None => tcx.types.unit,
                         Some(field_def) => {
                             let self_ty = field_def.ty(tcx, substs);
-                            let new_goal = goal.with(
+                            ecx.add_goal(goal.with(
                                 tcx,
                                 ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
-                            );
-                            let (_, certainty) = ecx.evaluate_goal(new_goal)?;
-                            return ecx.make_canonical_response(certainty);
+                            ));
+                            return ecx
+                                .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
                         }
                     }
                 }
@@ -408,12 +363,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                 ty::Tuple(elements) => match elements.last() {
                     None => tcx.types.unit,
                     Some(&self_ty) => {
-                        let new_goal = goal.with(
+                        ecx.add_goal(goal.with(
                             tcx,
                             ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
-                        );
-                        let (_, certainty) = ecx.evaluate_goal(new_goal)?;
-                        return ecx.make_canonical_response(certainty);
+                        ));
+                        return ecx
+                            .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
                     }
                 },
 
@@ -426,7 +381,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                 ),
             };
 
-            ecx.eq_term_and_make_canonical_response(goal, Certainty::Yes, metadata_ty)
+            ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into())?;
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
 
@@ -522,7 +478,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
         let discriminant = goal.predicate.self_ty().discriminant_ty(ecx.tcx());
-        ecx.probe(|ecx| ecx.eq_term_and_make_canonical_response(goal, Certainty::Yes, discriminant))
+        ecx.probe(|ecx| {
+            ecx.eq(goal.param_env, goal.predicate.term, discriminant.into())?;
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        })
     }
 }
 
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 f1b840aac55..83d77a69c00 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -39,9 +39,7 @@ impl<'tcx> SearchGraph<'tcx> {
     }
 
     pub(super) fn is_empty(&self) -> bool {
-        self.stack.is_empty()
-            && self.provisional_cache.is_empty()
-            && !self.overflow_data.did_overflow()
+        self.stack.is_empty() && self.provisional_cache.is_empty()
     }
 
     /// Whether we're currently in a cycle. This should only be used
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 7878539817c..8ab55c79fc4 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -47,16 +47,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             let impl_substs = ecx.fresh_substs_for_item(impl_def_id);
             let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
 
-            let mut nested_goals =
-                ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
+            ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
             let where_clause_bounds = tcx
                 .predicates_of(impl_def_id)
                 .instantiate(tcx, impl_substs)
                 .predicates
                 .into_iter()
                 .map(|pred| goal.with(tcx, pred));
-            nested_goals.extend(where_clause_bounds);
-            ecx.evaluate_all_and_make_canonical_response(nested_goals)
+            ecx.add_goals(where_clause_bounds);
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
 
@@ -73,13 +72,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             ecx.probe(|ecx| {
                 let assumption_trait_pred =
                     ecx.instantiate_binder_with_infer(poly_trait_pred);
-                let mut nested_goals = ecx.eq(
+                ecx.eq(
                     goal.param_env,
                     goal.predicate.trait_ref,
                     assumption_trait_pred.trait_ref,
                 )?;
-                nested_goals.extend(requirements);
-                ecx.evaluate_all_and_make_canonical_response(nested_goals)
+                ecx.add_goals(requirements);
+                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             })
         } else {
             Err(NoSolution)
@@ -98,7 +97,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             ecx.probe(|ecx| {
                 let assumption_trait_pred =
                     ecx.instantiate_binder_with_infer(poly_trait_pred);
-                let mut nested_goals = ecx.eq(
+                ecx.eq(
                     goal.param_env,
                     goal.predicate.trait_ref,
                     assumption_trait_pred.trait_ref,
@@ -108,9 +107,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                 let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
                     bug!("expected object type in `consider_object_bound_candidate`");
                 };
-                nested_goals.extend(
+                ecx.add_goals(
                     structural_traits::predicates_for_object_candidate(
-                        ecx,
+                        &ecx,
                         goal.param_env,
                         goal.predicate.trait_ref,
                         bounds,
@@ -118,8 +117,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                     .into_iter()
                     .map(|pred| goal.with(tcx, pred)),
                 );
-
-                ecx.evaluate_all_and_make_canonical_response(nested_goals)
+                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             })
         } else {
             Err(NoSolution)
@@ -166,9 +164,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             let nested_obligations = tcx
                 .predicates_of(goal.predicate.def_id())
                 .instantiate(tcx, goal.predicate.trait_ref.substs);
-            ecx.evaluate_all_and_make_canonical_response(
-                nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)).collect(),
-            )
+            ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)));
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
 
@@ -197,7 +194,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
         if goal.predicate.self_ty().has_non_region_infer() {
-            return ecx.make_canonical_response(Certainty::AMBIGUOUS);
+            return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
         }
 
         let tcx = ecx.tcx();
@@ -209,7 +206,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             && layout.layout.align().abi == usize_layout.align().abi
         {
             // FIXME: We could make this faster by making a no-constraints response
-            ecx.make_canonical_response(Certainty::Yes)
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         } else {
             Err(NoSolution)
         }
@@ -221,14 +218,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         goal_kind: ty::ClosureKind,
     ) -> QueryResult<'tcx> {
         let tcx = ecx.tcx();
-        let Some(tupled_inputs_and_output) =
-            structural_traits::extract_tupled_inputs_and_output_from_callable(
+        let tupled_inputs_and_output =
+            match structural_traits::extract_tupled_inputs_and_output_from_callable(
                 tcx,
                 goal.predicate.self_ty(),
                 goal_kind,
-            )? else {
-            return ecx.make_canonical_response(Certainty::AMBIGUOUS);
-        };
+            )? {
+                Some(a) => a,
+                None => {
+                    return ecx
+                        .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
+                }
+            };
         let output_is_sized_pred = tupled_inputs_and_output
             .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
 
@@ -247,7 +248,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
         if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
-            ecx.make_canonical_response(Certainty::Yes)
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         } else {
             Err(NoSolution)
         }
@@ -257,7 +258,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         _goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        ecx.make_canonical_response(Certainty::Yes)
+        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 
     fn consider_builtin_future_candidate(
@@ -277,7 +278,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         // Async generator unconditionally implement `Future`
         // Technically, we need to check that the future output type is Sized,
         // but that's already proven by the generator being WF.
-        ecx.make_canonical_response(Certainty::Yes)
+        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 
     fn consider_builtin_generator_candidate(
@@ -317,7 +318,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         let a_ty = goal.predicate.self_ty();
         let b_ty = goal.predicate.trait_ref.substs.type_at(1);
         if b_ty.is_ty_var() {
-            return ecx.make_canonical_response(Certainty::AMBIGUOUS);
+            return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
         }
         ecx.probe(|ecx| {
             match (a_ty.kind(), b_ty.kind()) {
@@ -326,7 +327,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                     // Dyn upcasting is handled separately, since due to upcasting,
                     // when there are two supertraits that differ by substs, we
                     // may return more than one query response.
-                    return Err(NoSolution);
+                    Err(NoSolution)
                 }
                 // `T` -> `dyn Trait` unsizing
                 (_, &ty::Dynamic(data, region, ty::Dyn)) => {
@@ -341,29 +342,26 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                     let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
                         return Err(NoSolution);
                     };
-                    let nested_goals: Vec<_> = data
-                        .iter()
-                        // Check that the type implements all of the predicates of the def-id.
-                        // (i.e. the principal, all of the associated types match, and any auto traits)
-                        .map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty)))
-                        .chain([
-                            // The type must be Sized to be unsized.
-                            goal.with(
-                                tcx,
-                                ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [a_ty])),
-                            ),
-                            // The type must outlive the lifetime of the `dyn` we're unsizing into.
-                            goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))),
-                        ])
-                        .collect();
-
-                    ecx.evaluate_all_and_make_canonical_response(nested_goals)
+                    // Check that the type implements all of the predicates of the def-id.
+                    // (i.e. the principal, all of the associated types match, and any auto traits)
+                    ecx.add_goals(
+                        data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
+                    );
+                    // The type must be Sized to be unsized.
+                    ecx.add_goal(
+                        goal.with(tcx, ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [a_ty]))),
+                    );
+                    // The type must outlive the lifetime of the `dyn` we're unsizing into.
+                    ecx.add_goal(
+                        goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))),
+                    );
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 }
                 // `[T; n]` -> `[T]` unsizing
                 (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
                     // We just require that the element type stays the same
-                    let nested_goals = ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
-                    ecx.evaluate_all_and_make_canonical_response(nested_goals)
+                    ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 }
                 // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
                 (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs))
@@ -397,15 +395,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
 
                     // Finally, we require that `TailA: Unsize<TailB>` for the tail field
                     // types.
-                    let mut nested_goals = ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
-                    nested_goals.push(goal.with(
+                    ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
+                    ecx.add_goal(goal.with(
                         tcx,
                         ty::Binder::dummy(
                             tcx.mk_trait_ref(goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
                         ),
                     ));
-
-                    ecx.evaluate_all_and_make_canonical_response(nested_goals)
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 }
                 // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
                 (&ty::Tuple(a_tys), &ty::Tuple(b_tys))
@@ -417,17 +414,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                     // Substitute just the tail field of B., and require that they're equal.
                     let unsized_a_ty =
                         tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied());
-                    let mut nested_goals = ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
+                    ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
 
                     // Similar to ADTs, require that the rest of the fields are equal.
-                    nested_goals.push(goal.with(
+                    ecx.add_goal(goal.with(
                         tcx,
                         ty::Binder::dummy(
                             tcx.mk_trait_ref(goal.predicate.def_id(), [*a_last_ty, *b_last_ty]),
                         ),
                     ));
-
-                    ecx.evaluate_all_and_make_canonical_response(nested_goals)
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 }
                 _ => Err(NoSolution),
             }
@@ -477,12 +473,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                 let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn);
 
                 // We also require that A's lifetime outlives B's lifetime.
-                let mut nested_obligations = ecx.eq(goal.param_env, new_a_ty, b_ty)?;
-                nested_obligations.push(
+                ecx.eq(goal.param_env, new_a_ty, b_ty)?;
+                ecx.add_goal(
                     goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region))),
                 );
-
-                ecx.evaluate_all_and_make_canonical_response(nested_obligations)
+                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             })
         };
 
@@ -516,7 +511,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         _goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
         // `DiscriminantKind` is automatically implemented for every type.
-        ecx.make_canonical_response(Certainty::Yes)
+        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 }
 
@@ -530,21 +525,23 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
     ) -> QueryResult<'tcx> {
-        self.probe(|this| {
-            this.evaluate_all_and_make_canonical_response(
-                constituent_tys(this, goal.predicate.self_ty())?
+        self.probe(|ecx| {
+            ecx.add_goals(
+                constituent_tys(ecx, goal.predicate.self_ty())?
                     .into_iter()
                     .map(|ty| {
                         goal.with(
-                            this.tcx(),
-                            ty::Binder::dummy(goal.predicate.with_self_ty(this.tcx(), ty)),
+                            ecx.tcx(),
+                            ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)),
                         )
                     })
-                    .collect(),
-            )
+                    .collect::<Vec<_>>(),
+            );
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
 
+    #[instrument(level = "debug", skip(self))]
     pub(super) fn compute_trait_goal(
         &mut self,
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
index d7d93377cf1..9817186b874 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
@@ -189,12 +189,28 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
     goal_kind: ty::ClosureKind,
 ) -> Result<Option<ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>)>>, NoSolution> {
     match *self_ty.kind() {
-        ty::FnDef(def_id, substs) => Ok(Some(
-            tcx.fn_sig(def_id)
-                .subst(tcx, substs)
-                .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())),
-        )),
-        ty::FnPtr(sig) => Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())))),
+        // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
+        ty::FnDef(def_id, substs) => {
+            let sig = tcx.fn_sig(def_id);
+            if sig.skip_binder().is_fn_trait_compatible()
+                && tcx.codegen_fn_attrs(def_id).target_features.is_empty()
+            {
+                Ok(Some(
+                    sig.subst(tcx, substs)
+                        .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())),
+                ))
+            } else {
+                Err(NoSolution)
+            }
+        }
+        // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
+        ty::FnPtr(sig) => {
+            if sig.is_fn_trait_compatible() {
+                Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output()))))
+            } else {
+                Err(NoSolution)
+            }
+        }
         ty::Closure(_, substs) => {
             let closure_substs = substs.as_closure();
             match closure_substs.kind_ty().to_opt_closure_kind() {
@@ -333,7 +349,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
             // FIXME: Technically this folder could be fallible?
             let nested = self
                 .ecx
-                .eq(self.param_env, alias_ty, proj.projection_ty)
+                .eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty)
                 .expect("expected to be able to unify goal projection with dyn's projection");
             // FIXME: Technically we could register these too..
             assert!(nested.is_empty(), "did not expect unification to have any nested goals");
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 1fb8659bb27..dbf6775afc2 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -7,6 +7,7 @@ use crate::errors::UnableToConstructConstantValue;
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::InferCtxt;
 use crate::traits::project::ProjectAndUnifyResult;
+use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::TypeVisitableExt;
@@ -179,8 +180,9 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         // At this point, we already have all of the bounds we need. FulfillmentContext is used
         // to store all of the necessary region/lifetime bounds in the InferContext, as well as
         // an additional sanity check.
-        let errors =
-            super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
+        let ocx = ObligationCtxt::new(&infcx);
+        ocx.register_bound(ObligationCause::dummy(), full_env, ty, trait_did);
+        let errors = ocx.select_all_or_error();
         if !errors.is_empty() {
             panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
         }
@@ -814,7 +816,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
 
                     match (evaluate(c1), evaluate(c2)) {
                         (Ok(c1), Ok(c2)) => {
-                            match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2)
+                            match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(DefineOpaqueTypes::No,c1, c2)
                             {
                                 Ok(_) => (),
                                 Err(_) => return false,
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 96a4b76af55..572d20b5368 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -17,7 +17,7 @@ use crate::traits::{
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{DefineOpaqueTypes, DefiningAnchor, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::util;
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
@@ -181,7 +181,7 @@ fn overlap_within_probe<'cx, 'tcx>(
     let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id);
     let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id);
 
-    let obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?;
+    let obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
     debug!("overlap: unification check succeeded");
 
     if overlap_mode.use_implicit_negative() {
@@ -207,20 +207,25 @@ fn overlap_within_probe<'cx, 'tcx>(
     Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
 }
 
-fn equate_impl_headers<'cx, 'tcx>(
-    selcx: &mut SelectionContext<'cx, 'tcx>,
-    impl1_header: &ty::ImplHeader<'tcx>,
-    impl2_header: &ty::ImplHeader<'tcx>,
+#[instrument(level = "debug", skip(infcx), ret)]
+fn equate_impl_headers<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    impl1: &ty::ImplHeader<'tcx>,
+    impl2: &ty::ImplHeader<'tcx>,
 ) -> Option<PredicateObligations<'tcx>> {
-    // Do `a` and `b` unify? If not, no overlap.
-    debug!("equate_impl_headers(impl1_header={:?}, impl2_header={:?}", impl1_header, impl2_header);
-    selcx
-        .infcx
-        .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
-        .define_opaque_types(true)
-        .eq_impl_headers(impl1_header, impl2_header)
-        .map(|infer_ok| infer_ok.obligations)
-        .ok()
+    let result = match (impl1.trait_ref, impl2.trait_ref) {
+        (Some(impl1_ref), Some(impl2_ref)) => infcx
+            .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+            .eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref),
+        (None, None) => infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
+            DefineOpaqueTypes::Yes,
+            impl1.self_ty,
+            impl2.self_ty,
+        ),
+        _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
+    };
+
+    result.map(|infer_ok| infer_ok.obligations).ok()
 }
 
 /// Given impl1 and impl2 check if both impls can be satisfied by a common type (including
@@ -325,7 +330,7 @@ fn equate<'tcx>(
 ) -> bool {
     // do the impls unify? If not, not disjoint.
     let Ok(InferOk { obligations: more_obligations, .. }) =
-        infcx.at(&ObligationCause::dummy(), impl_env).eq(subject1, subject2)
+        infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No,subject1, subject2)
     else {
         debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
         return true;
@@ -378,7 +383,10 @@ fn resolve_negative_obligation<'tcx>(
     };
 
     let param_env = o.param_env;
-    if !super::fully_solve_obligation(&infcx, o).is_empty() {
+    let ocx = ObligationCtxt::new(&infcx);
+    ocx.register_obligation(o);
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
         return false;
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 62d5e50dbc5..8acc31cd410 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -11,7 +11,7 @@ use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::canonical::{
     Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
 };
-use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
 use rustc_infer::traits::query::Fallible;
 use rustc_infer::traits::{
     FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
@@ -128,8 +128,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
     {
         self.infcx
             .at(cause, param_env)
-            .define_opaque_types(true)
-            .eq_exp(a_is_expected, a, b)
+            .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, a, b)
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
@@ -142,8 +141,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
     ) -> Result<(), TypeError<'tcx>> {
         self.infcx
             .at(cause, param_env)
-            .define_opaque_types(true)
-            .eq(expected, actual)
+            .eq(DefineOpaqueTypes::Yes, expected, actual)
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
@@ -157,8 +155,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
     ) -> Result<(), TypeError<'tcx>> {
         self.infcx
             .at(cause, param_env)
-            .define_opaque_types(true)
-            .sub(expected, actual)
+            .sub(DefineOpaqueTypes::Yes, expected, actual)
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
@@ -172,8 +169,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
     ) -> Result<(), TypeError<'tcx>> {
         self.infcx
             .at(cause, param_env)
-            .define_opaque_types(true)
-            .sup(expected, actual)
+            .sup(DefineOpaqueTypes::Yes, expected, actual)
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
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 b3bf9ad599a..a9c4e126816 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
@@ -149,9 +149,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs));
         let trait_ref = trait_ref.skip_binder();
 
-        let body_hir = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
-        let mut flags =
-            vec![(sym::ItemContext, self.describe_enclosure(body_hir).map(|s| s.to_owned()))];
+        let mut flags = vec![];
+        // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs,
+        // but I guess we could synthesize one here. We don't see any errors that rely on
+        // that yet, though.
+        let enclosure =
+            if let Some(body_hir) = self.tcx.opt_local_def_id_to_hir_id(obligation.cause.body_id) {
+                self.describe_enclosure(body_hir).map(|s| s.to_owned())
+            } else {
+                None
+            };
+        flags.push((sym::ItemContext, enclosure));
 
         match obligation.cause.code() {
             ObligationCauseCode::BuiltinDerivedObligation(..)
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 11567ff39dd..b501840b926 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -420,6 +420,7 @@ fn suggest_restriction<'tcx>(
 ) {
     if hir_generics.where_clause_span.from_expansion()
         || hir_generics.where_clause_span.desugaring_kind().is_some()
+        || projection.map_or(false, |projection| tcx.opt_rpitit_info(projection.def_id).is_some())
     {
         return;
     }
@@ -2944,9 +2945,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             ObligationCauseCode::SizedYieldType => {
                 err.note("the yield type of a generator must have a statically known size");
             }
-            ObligationCauseCode::SizedBoxType => {
-                err.note("the type of a box expression must have a statically known size");
-            }
             ObligationCauseCode::AssignmentLhsSized => {
                 err.note("the left-hand-side of an assignment must have a statically known size");
             }
@@ -3033,8 +3031,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     }
                 };
 
-                let identity_future = tcx.require_lang_item(LangItem::IdentityFuture, None);
-
                 // Don't print the tuple of capture types
                 'print: {
                     if !is_upvar_tys_infer_tuple {
@@ -3047,12 +3043,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 None => err.note(&msg),
                             },
                             ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
-                                // Avoid printing the future from `core::future::identity_future`, it's not helpful
-                                if tcx.parent(*def_id) == identity_future {
-                                    break 'print;
-                                }
-
-                                // If the previous type is `identity_future`, this is the future generated by the body of an async function.
+                                // If the previous type is async fn, this is the future generated by the body of an async function.
                                 // Avoid printing it twice (it was already printed in the `ty::Generator` arm below).
                                 let is_future = tcx.ty_is_opaque_future(ty);
                                 debug!(
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 944436ab82f..23754480fcf 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -2,6 +2,7 @@ use crate::infer::{InferCtxt, TyOrConstInferVar};
 use rustc_data_structures::obligation_forest::ProcessResult;
 use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
+use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::ProjectionCacheKey;
 use rustc_infer::traits::{SelectionError, TraitEngine, TraitObligation};
 use rustc_middle::mir::interpret::ErrorHandled;
@@ -210,6 +211,29 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
     type Error = FulfillmentErrorCode<'tcx>;
     type OUT = Outcome<Self::Obligation, Self::Error>;
 
+    /// Compared to `needs_process_obligation` this and its callees
+    /// contain some optimizations that come at the price of false negatives.
+    ///
+    /// They
+    /// - reduce branching by covering only the most common case
+    /// - take a read-only view of the unification tables which allows skipping undo_log
+    ///   construction.
+    /// - bail out on value-cache misses in ena to avoid pointer chasing
+    /// - hoist RefCell locking out of the loop
+    #[inline]
+    fn skippable_obligations<'b>(
+        &'b self,
+        it: impl Iterator<Item = &'b Self::Obligation>,
+    ) -> usize {
+        let is_unchanged = self.selcx.infcx.is_ty_infer_var_definitely_unchanged();
+
+        it.take_while(|o| match o.stalled_on.as_slice() {
+            [o] => is_unchanged(*o),
+            _ => false,
+        })
+        .count()
+    }
+
     /// Identifies whether a predicate obligation needs processing.
     ///
     /// This is always inlined because it has a single callsite and it is
@@ -515,7 +539,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                                 if let Ok(new_obligations) = infcx
                                     .at(&obligation.cause, obligation.param_env)
                                     .trace(c1, c2)
-                                    .eq(a.substs, b.substs)
+                                    .eq(DefineOpaqueTypes::No, a.substs, b.substs)
                                 {
                                     return ProcessResult::Changed(mk_pending(
                                         new_obligations.into_obligations(),
@@ -524,8 +548,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                             }
                             (_, Unevaluated(_)) | (Unevaluated(_), _) => (),
                             (_, _) => {
-                                if let Ok(new_obligations) =
-                                    infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2)
+                                if let Ok(new_obligations) = infcx
+                                    .at(&obligation.cause, obligation.param_env)
+                                    .eq(DefineOpaqueTypes::No, c1, c2)
                                 {
                                     return ProcessResult::Changed(mk_pending(
                                         new_obligations.into_obligations(),
@@ -565,12 +590,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
 
                     match (evaluate(c1), evaluate(c2)) {
                         (Ok(c1), Ok(c2)) => {
-                            match self
-                                .selcx
-                                .infcx
-                                .at(&obligation.cause, obligation.param_env)
-                                .eq(c1, c2)
-                            {
+                            match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
+                                DefineOpaqueTypes::No,
+                                c1,
+                                c2,
+                            ) {
                                 Ok(inf_ok) => {
                                     ProcessResult::Changed(mk_pending(inf_ok.into_obligations()))
                                 }
@@ -610,12 +634,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     bug!("AliasEq is only used for new solver")
                 }
                 ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
-                    match self
-                        .selcx
-                        .infcx
-                        .at(&obligation.cause, obligation.param_env)
-                        .eq(ct.ty(), ty)
-                    {
+                    match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
+                        DefineOpaqueTypes::No,
+                        ct.ty(),
+                        ty,
+                    ) {
                         Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
                         Err(_) => ProcessResult::Error(FulfillmentErrorCode::CodeSelectionError(
                             SelectionError::Unimplemented,
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index bfeda88a6d4..b27a3929078 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -30,7 +30,7 @@ use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
-use rustc_span::def_id::{DefId, CRATE_DEF_ID};
+use rustc_span::def_id::DefId;
 use rustc_span::Span;
 
 use std::fmt::Debug;
@@ -63,9 +63,7 @@ pub use self::util::{
     elaborate_trait_ref, elaborate_trait_refs,
 };
 pub use self::util::{expand_trait_aliases, TraitAliasExpander};
-pub use self::util::{
-    get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
-};
+pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
 pub use self::util::{
     supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type,
     SupertraitDefIds, Supertraits,
@@ -131,29 +129,23 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
     def_id: DefId,
-    span: Span,
 ) -> bool {
     let trait_ref = ty::Binder::dummy(infcx.tcx.mk_trait_ref(def_id, [ty]));
-    pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const(), span)
+    pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const())
 }
 
-#[instrument(level = "debug", skip(infcx, param_env, span, pred), ret)]
+/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist?
+///
+/// Ping me on zulip if you want to use this method and need help with finding
+/// an appropriate replacement.
+#[instrument(level = "debug", skip(infcx, param_env, pred), ret)]
 fn pred_known_to_hold_modulo_regions<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>,
-    span: Span,
 ) -> bool {
     let has_non_region_infer = pred.has_non_region_infer();
-    let obligation = Obligation {
-        param_env,
-        // We can use a dummy node-id here because we won't pay any mind
-        // to region obligations that arise (there shouldn't really be any
-        // anyhow).
-        cause: ObligationCause::misc(span, CRATE_DEF_ID),
-        recursion_depth: 0,
-        predicate: pred.to_predicate(infcx.tcx),
-    };
+    let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred);
 
     let result = infcx.evaluate_obligation_no_overflow(&obligation);
     debug!(?result);
@@ -166,14 +158,13 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
         // this function's result remains infallible, we must confirm
         // that guess. While imperfect, I believe this is sound.
 
-        // FIXME(@lcnr): this function doesn't seem right.
-        //
         // The handling of regions in this area of the code is terrible,
         // see issue #29149. We should be able to improve on this with
         // NLL.
-        let errors = fully_solve_obligation(infcx, obligation);
-
-        match &errors[..] {
+        let ocx = ObligationCtxt::new(infcx);
+        ocx.register_obligation(obligation);
+        let errors = ocx.select_all_or_error();
+        match errors.as_slice() {
             [] => true,
             errors => {
                 debug!(?errors);
@@ -389,43 +380,6 @@ where
     Ok(resolved_value)
 }
 
-/// Process an obligation (and any nested obligations that come from it) to
-/// completion, returning any errors
-pub fn fully_solve_obligation<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    obligation: PredicateObligation<'tcx>,
-) -> Vec<FulfillmentError<'tcx>> {
-    fully_solve_obligations(infcx, [obligation])
-}
-
-/// Process a set of obligations (and any nested obligations that come from them)
-/// to completion
-pub fn fully_solve_obligations<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
-) -> Vec<FulfillmentError<'tcx>> {
-    let ocx = ObligationCtxt::new(infcx);
-    ocx.register_obligations(obligations);
-    ocx.select_all_or_error()
-}
-
-/// Process a bound (and any nested obligations that come from it) to completion.
-/// This is a convenience function for traits that have no generic arguments, such
-/// as auto traits, and builtin traits like Copy or Sized.
-pub fn fully_solve_bound<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    cause: ObligationCause<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
-    bound: DefId,
-) -> Vec<FulfillmentError<'tcx>> {
-    let tcx = infcx.tcx;
-    let trait_ref = tcx.mk_trait_ref(bound, [ty]);
-    let obligation = Obligation::new(tcx, cause, param_env, ty::Binder::dummy(trait_ref));
-
-    fully_solve_obligation(infcx, obligation)
-}
-
 /// Normalizes the predicates and checks whether they hold in an empty environment. If this
 /// returns true, then either normalize encountered an error or one of the predicates did not
 /// hold. Used when creating vtables to check for unsatisfiable methods.
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 4eacb5211f7..038f8964471 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -13,15 +13,14 @@ use super::{elaborate_predicates, elaborate_trait_ref};
 use crate::infer::TyCtxtInferExt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{self, Obligation, ObligationCause};
-use hir::def::DefKind;
 use rustc_errors::{DelayDm, FatalError, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
-use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::{
     self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
+use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
@@ -140,6 +139,10 @@ fn object_safety_violations_for_trait(
     if !spans.is_empty() {
         violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
     }
+    let spans = super_predicates_have_non_lifetime_binders(tcx, trait_def_id);
+    if !spans.is_empty() {
+        violations.push(ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans));
+    }
 
     violations.extend(
         tcx.associated_items(trait_def_id)
@@ -157,6 +160,7 @@ fn object_safety_violations_for_trait(
                 .in_definition_order()
                 .filter(|item| item.kind == ty::AssocKind::Type)
                 .filter(|item| !tcx.generics_of(item.def_id).params.is_empty())
+                .filter(|item| tcx.opt_rpitit_info(item.def_id).is_none())
                 .map(|item| {
                     let ident = item.ident(tcx);
                     ObjectSafetyViolation::GAT(ident.name, ident.span)
@@ -348,6 +352,21 @@ fn predicate_references_self<'tcx>(
     }
 }
 
+fn super_predicates_have_non_lifetime_binders(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+) -> SmallVec<[Span; 1]> {
+    // If non_lifetime_binders is disabled, then exit early
+    if !tcx.features().non_lifetime_binders {
+        return SmallVec::new();
+    }
+    tcx.super_predicates_of(trait_def_id)
+        .predicates
+        .iter()
+        .filter_map(|(pred, span)| pred.has_non_region_late_bound().then_some(*span))
+        .collect()
+}
+
 fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
     generics_require_sized_self(tcx, trait_def_id)
 }
@@ -854,7 +873,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
                     }
                 }
                 ty::Alias(ty::Projection, ref data)
-                    if self.tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder =>
+                    if self.tcx.is_impl_trait_in_trait(data.def_id) =>
                 {
                     // We'll deny these later in their own pass
                     ControlFlow::Continue(())
@@ -921,7 +940,7 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>(
     ty.skip_binder().walk().find_map(|arg| {
         if let ty::GenericArgKind::Type(ty) = arg.unpack()
             && let ty::Alias(ty::Projection, proj) = ty.kind()
-            && tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
+            && tcx.is_impl_trait_in_trait(proj.def_id)
         {
             Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.def_id)))
         } else {
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 6cb64ad574f..bac02f2d383 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -1,7 +1,7 @@
 use crate::infer::InferCtxt;
 use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
 use crate::traits::query::NoSolution;
-use crate::traits::ObligationCause;
+use crate::traits::{ObligationCause, ObligationCtxt};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_middle::ty::{self, ParamEnv, Ty};
 use rustc_span::def_id::LocalDefId;
@@ -71,22 +71,23 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
 
         if let Some(constraints) = constraints {
             debug!(?constraints);
+            if !constraints.member_constraints.is_empty() {
+                span_bug!(span, "{:#?}", constraints.member_constraints);
+            }
+
             // Instantiation may have produced new inference variables and constraints on those
             // variables. Process these constraints.
+            let ocx = ObligationCtxt::new(self);
             let cause = ObligationCause::misc(span, body_id);
-            let errors = super::fully_solve_obligations(
-                self,
-                constraints.outlives.iter().map(|constraint| {
-                    self.query_outlives_constraint_to_obligation(
-                        *constraint,
-                        cause.clone(),
-                        param_env,
-                    )
-                }),
-            );
-            if !constraints.member_constraints.is_empty() {
-                span_bug!(span, "{:#?}", constraints.member_constraints);
+            for &constraint in &constraints.outlives {
+                ocx.register_obligation(self.query_outlives_constraint_to_obligation(
+                    constraint,
+                    cause.clone(),
+                    param_env,
+                ));
             }
+
+            let errors = ocx.select_all_or_error();
             if !errors.is_empty() {
                 self.tcx.sess.delay_span_bug(
                     span,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 01075d7c55a..b8d9cff9c48 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -28,6 +28,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::at::At;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
+use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::ImplSourceBuiltinData;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
@@ -285,12 +286,12 @@ fn project_and_unify_type<'cx, 'tcx>(
         );
     obligations.extend(new);
 
-    match infcx
-        .at(&obligation.cause, obligation.param_env)
-        // This is needed to support nested opaque types like `impl Fn() -> impl Trait`
-        .define_opaque_types(true)
-        .eq(normalized, actual)
-    {
+    // Need to define opaque types to support nested opaque types like `impl Fn() -> impl Trait`
+    match infcx.at(&obligation.cause, obligation.param_env).eq(
+        DefineOpaqueTypes::Yes,
+        normalized,
+        actual,
+    ) {
         Ok(InferOk { obligations: inferred_obligations, value: () }) => {
             obligations.extend(inferred_obligations);
             ProjectAndUnifyResult::Holds(obligations)
@@ -467,6 +468,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
             return ty;
         }
 
+        let (kind, data) = match *ty.kind() {
+            ty::Alias(kind, alias_ty) => (kind, alias_ty),
+            _ => return ty.super_fold_with(self),
+        };
+
         // We try to be a little clever here as a performance optimization in
         // cases where there are nested projections under binders.
         // For example:
@@ -490,13 +496,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
         // replace bound vars if the current type is a `Projection` and we need
         // to make sure we don't forget to fold the substs regardless.
 
-        match *ty.kind() {
+        match kind {
             // This is really important. While we *can* handle this, this has
             // severe performance implications for large opaque types with
             // late-bound regions. See `issue-88862` benchmark.
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
-                if !substs.has_escaping_bound_vars() =>
-            {
+            ty::Opaque if !data.substs.has_escaping_bound_vars() => {
                 // Only normalize `impl Trait` outside of type inference, usually in codegen.
                 match self.param_env.reveal() {
                     Reveal::UserFacing => ty.super_fold_with(self),
@@ -512,8 +516,8 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
                             );
                         }
 
-                        let substs = substs.fold_with(self);
-                        let generic_ty = self.interner().type_of(def_id);
+                        let substs = data.substs.fold_with(self);
+                        let generic_ty = self.interner().type_of(data.def_id);
                         let concrete_ty = generic_ty.subst(self.interner(), substs);
                         self.depth += 1;
                         let folded_ty = self.fold_ty(concrete_ty);
@@ -522,8 +526,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
                     }
                 }
             }
+            ty::Opaque => ty.super_fold_with(self),
 
-            ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => {
+            ty::Projection if !data.has_escaping_bound_vars() => {
                 // This branch is *mostly* just an optimization: when we don't
                 // have escaping bound vars, we don't need to replace them with
                 // placeholders (see branch below). *Also*, we know that we can
@@ -562,7 +567,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
                 normalized_ty.ty().unwrap()
             }
 
-            ty::Alias(ty::Projection, data) => {
+            ty::Projection => {
                 // If there are escaping bound vars, we temporarily replace the
                 // bound vars with placeholders. Note though, that in the case
                 // that we still can't project for whatever reason (e.g. self
@@ -611,8 +616,6 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
                 );
                 normalized_ty
             }
-
-            _ => ty.super_fold_with(self),
         }
     }
 
@@ -1295,7 +1298,7 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
 ) {
     let tcx = selcx.tcx();
     if tcx.def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder {
-        let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id);
+        let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id);
 
         let trait_def_id = tcx.parent(trait_fn_def_id);
         let trait_substs =
@@ -2064,7 +2067,11 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
 
     debug!(?cache_projection, ?obligation_projection);
 
-    match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
+    match infcx.at(cause, param_env).eq(
+        DefineOpaqueTypes::No,
+        cache_projection,
+        obligation_projection,
+    ) {
         Ok(InferOk { value: _, obligations }) => {
             nested_obligations.extend(obligations);
             assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
@@ -2193,7 +2200,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
     let tcx = selcx.tcx();
     let mut obligations = data.nested;
 
-    let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id);
+    let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id);
     let leaf_def = match specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) {
         Ok(assoc_ty) => assoc_ty,
         Err(guar) => return Progress::error(tcx, guar),
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index b0cec3ce7a3..a986a9b6a71 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -197,23 +197,30 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
             return Ok(*ty);
         }
 
+        let (kind, data) = match *ty.kind() {
+            ty::Alias(kind, data) => (kind, data),
+            _ => {
+                let res = ty.try_super_fold_with(self)?;
+                self.cache.insert(ty, res);
+                return Ok(res);
+            }
+        };
+
         // See note in `rustc_trait_selection::traits::project` about why we
         // wait to fold the substs.
 
         // Wrap this in a closure so we don't accidentally return from the outer function
-        let res = match *ty.kind() {
+        let res = match kind {
             // This is really important. While we *can* handle this, this has
             // severe performance implications for large opaque types with
             // late-bound regions. See `issue-88862` benchmark.
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
-                if !substs.has_escaping_bound_vars() =>
-            {
+            ty::Opaque if !data.substs.has_escaping_bound_vars() => {
                 // Only normalize `impl Trait` outside of type inference, usually in codegen.
                 match self.param_env.reveal() {
                     Reveal::UserFacing => ty.try_super_fold_with(self)?,
 
                     Reveal::All => {
-                        let substs = substs.try_fold_with(self)?;
+                        let substs = data.substs.try_fold_with(self)?;
                         let recursion_limit = self.interner().recursion_limit();
                         if !recursion_limit.value_within_limit(self.anon_depth) {
                             // A closure or generator may have itself as in its upvars.
@@ -228,7 +235,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
                             return ty.try_super_fold_with(self);
                         }
 
-                        let generic_ty = self.interner().type_of(def_id);
+                        let generic_ty = self.interner().type_of(data.def_id);
                         let concrete_ty = generic_ty.subst(self.interner(), substs);
                         self.anon_depth += 1;
                         if concrete_ty == ty {
@@ -248,62 +255,22 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
                 }
             }
 
-            ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => {
-                // This branch is just an optimization: when we don't have escaping bound vars,
-                // we don't need to replace them with placeholders (see branch below).
-
-                let tcx = self.infcx.tcx;
-                let data = data.try_fold_with(self)?;
-
-                let mut orig_values = OriginalQueryValues::default();
-                // HACK(matthewjasper) `'static` is special-cased in selection,
-                // so we cannot canonicalize it.
-                let c_data = self
-                    .infcx
-                    .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
-                debug!("QueryNormalizer: c_data = {:#?}", c_data);
-                debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
-                let result = tcx.normalize_projection_ty(c_data)?;
-                // We don't expect ambiguity.
-                if result.is_ambiguous() {
-                    // Rustdoc normalizes possibly not well-formed types, so only
-                    // treat this as a bug if we're not in rustdoc.
-                    if !tcx.sess.opts.actually_rustdoc {
-                        tcx.sess.delay_span_bug(
-                            DUMMY_SP,
-                            format!("unexpected ambiguity: {:?} {:?}", c_data, result),
-                        );
-                    }
-                    return Err(NoSolution);
-                }
-                let InferOk { value: result, obligations } =
-                    self.infcx.instantiate_query_response_and_region_obligations(
-                        self.cause,
-                        self.param_env,
-                        &orig_values,
-                        result,
-                    )?;
-                debug!("QueryNormalizer: result = {:#?}", result);
-                debug!("QueryNormalizer: obligations = {:#?}", obligations);
-                self.obligations.extend(obligations);
-
-                let res = result.normalized_ty;
-                // `tcx.normalize_projection_ty` may normalize to a type that still has
-                // unevaluated consts, so keep normalizing here if that's the case.
-                if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
-                    res.try_super_fold_with(self)?
-                } else {
-                    res
-                }
-            }
+            ty::Opaque => ty.try_super_fold_with(self)?,
 
-            ty::Alias(ty::Projection, data) => {
+            ty::Projection => {
                 // See note in `rustc_trait_selection::traits::project`
 
                 let tcx = self.infcx.tcx;
                 let infcx = self.infcx;
-                let (data, mapped_regions, mapped_types, mapped_consts) =
-                    BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
+                // Just an optimization: When we don't have escaping bound vars,
+                // we don't need to replace them with placeholders.
+                let (data, maps) = if data.has_escaping_bound_vars() {
+                    let (data, mapped_regions, mapped_types, mapped_consts) =
+                        BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
+                    (data, Some((mapped_regions, mapped_types, mapped_consts)))
+                } else {
+                    (data, None)
+                };
                 let data = data.try_fold_with(self)?;
 
                 let mut orig_values = OriginalQueryValues::default();
@@ -337,14 +304,18 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
                 debug!("QueryNormalizer: result = {:#?}", result);
                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
                 self.obligations.extend(obligations);
-                let res = PlaceholderReplacer::replace_placeholders(
-                    infcx,
-                    mapped_regions,
-                    mapped_types,
-                    mapped_consts,
-                    &self.universes,
-                    result.normalized_ty,
-                );
+                let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps {
+                    PlaceholderReplacer::replace_placeholders(
+                        infcx,
+                        mapped_regions,
+                        mapped_types,
+                        mapped_consts,
+                        &self.universes,
+                        result.normalized_ty,
+                    )
+                } else {
+                    result.normalized_ty
+                };
                 // `tcx.normalize_projection_ty` may normalize to a type that still has
                 // unevaluated consts, so keep normalizing here if that's the case.
                 if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
@@ -353,8 +324,6 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
                     res
                 }
             }
-
-            _ => ty.try_super_fold_with(self)?,
         };
 
         self.cache.insert(ty, res);
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 6bf3ed0d0e2..8f1b05c1190 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -1,8 +1,8 @@
 use crate::infer::canonical::query_response;
 use crate::infer::{InferCtxt, InferOk};
-use crate::traits;
 use crate::traits::query::type_op::TypeOpOutput;
 use crate::traits::query::Fallible;
+use crate::traits::ObligationCtxt;
 use rustc_infer::infer::region_constraints::RegionConstraintData;
 use rustc_span::source_map::DUMMY_SP;
 
@@ -73,7 +73,9 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
     );
 
     let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
-    let errors = traits::fully_solve_obligations(infcx, obligations);
+    let ocx = ObligationCtxt::new(infcx);
+    ocx.register_obligations(obligations);
+    let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
         infcx.tcx.sess.diagnostic().delay_span_bug(
             DUMMY_SP,
@@ -82,9 +84,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
     }
 
     let region_obligations = infcx.take_registered_region_obligations();
-
     let region_constraint_data = infcx.take_and_reset_region_constraints();
-
     let region_constraints = query_response::make_query_region_constraints(
         infcx.tcx,
         region_obligations
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 3182af989f0..e06eff34df2 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -11,7 +11,6 @@ use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
 use rustc_middle::ty::fast_reject::TreatProjections;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
-use rustc_target::spec::abi::Abi;
 
 use crate::traits;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
@@ -291,6 +290,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return;
         }
 
+        // Keep this funtion in sync with extract_tupled_inputs_and_output_from_callable
+        // until the old solver (and thus this function) is removed.
+
         // Okay to skip binder because what we are inspecting doesn't involve bound regions.
         let self_ty = obligation.self_ty().skip_binder();
         match *self_ty.kind() {
@@ -299,31 +301,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 candidates.ambiguous = true; // Could wind up being a fn() type.
             }
             // Provide an impl, but only for suitable `fn` pointers.
-            ty::FnPtr(_) => {
-                if let ty::FnSig {
-                    unsafety: hir::Unsafety::Normal,
-                    abi: Abi::Rust,
-                    c_variadic: false,
-                    ..
-                } = self_ty.fn_sig(self.tcx()).skip_binder()
-                {
+            ty::FnPtr(sig) => {
+                if sig.is_fn_trait_compatible() {
                     candidates.vec.push(FnPointerCandidate { is_const: false });
                 }
             }
             // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
             ty::FnDef(def_id, _) => {
-                if let ty::FnSig {
-                    unsafety: hir::Unsafety::Normal,
-                    abi: Abi::Rust,
-                    c_variadic: false,
-                    ..
-                } = self_ty.fn_sig(self.tcx()).skip_binder()
+                if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible()
+                    && self.tcx().codegen_fn_attrs(def_id).target_features.is_empty()
                 {
-                    if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() {
-                        candidates
-                            .vec
-                            .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
-                    }
+                    candidates
+                        .vec
+                        .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
                 }
             }
             _ => {}
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index ee41d840bae..eb354bc3f50 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -8,8 +8,8 @@
 //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::lang_items::LangItem;
-use rustc_infer::infer::InferOk;
 use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::ty::{
     self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate,
     TraitRef, Ty, TyCtxt, TypeVisitableExt,
@@ -18,7 +18,7 @@ use rustc_session::config::TraitSolver;
 use rustc_span::def_id::DefId;
 
 use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
-use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def};
+use crate::traits::util::{self, closure_trait_ref_and_return_type};
 use crate::traits::vtable::{
     count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset,
     VtblSegment,
@@ -177,7 +177,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligations.extend(self.infcx.commit_if_ok(|_| {
             self.infcx
                 .at(&obligation.cause, obligation.param_env)
-                .sup(placeholder_trait_predicate, candidate)
+                .sup(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
                 .map(|InferOk { obligations, .. }| obligations)
                 .map_err(|_| Unimplemented)
         })?);
@@ -253,15 +253,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             };
 
             let cause = obligation.derived_cause(BuiltinDerivedObligation);
-            ensure_sufficient_stack(|| {
-                self.collect_predicates_for_types(
-                    obligation.param_env,
-                    cause,
-                    obligation.recursion_depth + 1,
-                    trait_def,
-                    nested,
-                )
-            })
+            self.collect_predicates_for_types(
+                obligation.param_env,
+                cause,
+                obligation.recursion_depth + 1,
+                trait_def,
+                nested,
+            )
         } else {
             vec![]
         };
@@ -462,7 +460,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         nested.extend(self.infcx.commit_if_ok(|_| {
             self.infcx
                 .at(&obligation.cause, obligation.param_env)
-                .sup(obligation_trait_ref, upcast_trait_ref)
+                .sup(DefineOpaqueTypes::No, obligation_trait_ref, upcast_trait_ref)
                 .map(|InferOk { obligations, .. }| obligations)
                 .map_err(|_| Unimplemented)
         })?);
@@ -827,11 +825,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 )
             });
 
+        // needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            // needed for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs
-            .define_opaque_types(true)
-            .sup(obligation_trait_ref, expected_trait_ref)
+            .sup(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
             .map(|InferOk { mut obligations, .. }| {
                 obligations.extend(nested);
                 obligations
@@ -896,7 +893,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 let InferOk { obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
-                    .sup(target, source_trait)
+                    .sup(DefineOpaqueTypes::No, target, source_trait)
                     .map_err(|_| Unimplemented)?;
                 nested.extend(obligations);
 
@@ -995,7 +992,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 let InferOk { obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
-                    .sup(target, source_trait)
+                    .sup(DefineOpaqueTypes::No, target, source_trait)
                     .map_err(|_| Unimplemented)?;
                 nested.extend(obligations);
 
@@ -1066,7 +1063,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 let InferOk { obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
-                    .eq(b, a)
+                    .eq(DefineOpaqueTypes::No, b, a)
                     .map_err(|_| Unimplemented)?;
                 nested.extend(obligations);
             }
@@ -1114,19 +1111,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 let InferOk { obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
-                    .eq(target, new_struct)
+                    .eq(DefineOpaqueTypes::No, target, new_struct)
                     .map_err(|_| Unimplemented)?;
                 nested.extend(obligations);
 
                 // Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate.
-                nested.push(predicate_for_trait_def(
+                let tail_unsize_obligation = obligation.with(
                     tcx,
-                    obligation.param_env,
-                    obligation.cause.clone(),
-                    obligation.predicate.def_id(),
-                    obligation.recursion_depth + 1,
-                    [source_tail, target_tail],
-                ));
+                    tcx.mk_trait_ref(obligation.predicate.def_id(), [source_tail, target_tail]),
+                );
+                nested.push(tail_unsize_obligation);
             }
 
             // `(.., T)` -> `(.., U)`
@@ -1144,21 +1138,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 let InferOk { obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
-                    .eq(target, new_tuple)
+                    .eq(DefineOpaqueTypes::No, target, new_tuple)
                     .map_err(|_| Unimplemented)?;
                 nested.extend(obligations);
 
-                // Construct the nested `T: Unsize<U>` predicate.
-                nested.push(ensure_sufficient_stack(|| {
-                    predicate_for_trait_def(
-                        tcx,
-                        obligation.param_env,
-                        obligation.cause.clone(),
-                        obligation.predicate.def_id(),
-                        obligation.recursion_depth + 1,
-                        [a_last, b_last],
-                    )
-                }));
+                // Add a nested `T: Unsize<U>` predicate.
+                let last_unsize_obligation = obligation
+                    .with(tcx, tcx.mk_trait_ref(obligation.predicate.def_id(), [a_last, b_last]));
+                nested.push(last_unsize_obligation);
             }
 
             _ => bug!("source: {source}, target: {target}"),
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 38cdaddc1e7..b8758ad9323 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -17,7 +17,7 @@ use super::project;
 use super::project::normalize_with_depth_to;
 use super::project::ProjectionTyObligation;
 use super::util;
-use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
+use super::util::closure_trait_ref_and_return_type;
 use super::wf;
 use super::{
     ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation,
@@ -38,6 +38,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::Diagnostic;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_infer::traits::TraitEngine;
 use rustc_infer::traits::TraitEngineExt;
@@ -594,7 +595,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             self.evaluate_predicates_recursively_in_new_solver(predicates)
         } else {
             let mut result = EvaluatedToOk;
-            for obligation in predicates {
+            for mut obligation in predicates {
+                obligation.set_depth_from_parent(stack.depth());
                 let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
                 if let EvaluatedToErr = eval {
                     // fast-path - EvaluatedToErr is the top of the lattice,
@@ -660,12 +662,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     let p = bound_predicate.rebind(p);
                     // Does this code ever run?
                     match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
-                        Ok(Ok(InferOk { mut obligations, .. })) => {
-                            self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
-                            self.evaluate_predicates_recursively(
-                                previous_stack,
-                                obligations.into_iter(),
-                            )
+                        Ok(Ok(InferOk { obligations, .. })) => {
+                            self.evaluate_predicates_recursively(previous_stack, obligations)
                         }
                         Ok(Err(_)) => Ok(EvaluatedToErr),
                         Err(..) => Ok(EvaluatedToAmbig),
@@ -676,12 +674,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     let p = bound_predicate.rebind(p);
                     // Does this code ever run?
                     match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) {
-                        Ok(Ok(InferOk { mut obligations, .. })) => {
-                            self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
-                            self.evaluate_predicates_recursively(
-                                previous_stack,
-                                obligations.into_iter(),
-                            )
+                        Ok(Ok(InferOk { obligations, .. })) => {
+                            self.evaluate_predicates_recursively(previous_stack, obligations)
                         }
                         Ok(Err(_)) => Ok(EvaluatedToErr),
                         Err(..) => Ok(EvaluatedToAmbig),
@@ -754,9 +748,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         arg,
                         obligation.cause.span,
                     ) {
-                        Some(mut obligations) => {
-                            self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
-
+                        Some(obligations) => {
                             cache.wf_args.borrow_mut().push((arg, previous_stack.depth()));
                             let result =
                                 self.evaluate_predicates_recursively(previous_stack, obligations);
@@ -825,10 +817,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                     }
                                 }
 
-                                self.add_depth(
-                                    subobligations.iter_mut(),
-                                    obligation.recursion_depth,
-                                );
+                                // Need to explicitly set the depth of nested goals here as
+                                // projection obligations can cycle by themselves and in
+                                // `evaluate_predicates_recursively` we only add the depth
+                                // for parent trait goals because only these get added to the
+                                // `TraitObligationStackList`.
+                                for subobligation in subobligations.iter_mut() {
+                                    subobligation.set_depth_from_parent(obligation.recursion_depth);
+                                }
                                 let res = self.evaluate_predicates_recursively(
                                     previous_stack,
                                     subobligations,
@@ -908,38 +904,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 if a.def.did == b.def.did
                                     && tcx.def_kind(a.def.did) == DefKind::AssocConst =>
                             {
-                                if let Ok(new_obligations) = self
+                                if let Ok(InferOk { obligations, value: () }) = self
                                     .infcx
                                     .at(&obligation.cause, obligation.param_env)
                                     .trace(c1, c2)
-                                    .eq(a.substs, b.substs)
+                                    .eq(DefineOpaqueTypes::No, a.substs, b.substs)
                                 {
-                                    let mut obligations = new_obligations.obligations;
-                                    self.add_depth(
-                                        obligations.iter_mut(),
-                                        obligation.recursion_depth,
-                                    );
                                     return self.evaluate_predicates_recursively(
                                         previous_stack,
-                                        obligations.into_iter(),
+                                        obligations,
                                     );
                                 }
                             }
                             (_, Unevaluated(_)) | (Unevaluated(_), _) => (),
                             (_, _) => {
-                                if let Ok(new_obligations) = self
+                                if let Ok(InferOk { obligations, value: () }) = self
                                     .infcx
                                     .at(&obligation.cause, obligation.param_env)
-                                    .eq(c1, c2)
+                                    .eq(DefineOpaqueTypes::No, c1, c2)
                                 {
-                                    let mut obligations = new_obligations.obligations;
-                                    self.add_depth(
-                                        obligations.iter_mut(),
-                                        obligation.recursion_depth,
-                                    );
                                     return self.evaluate_predicates_recursively(
                                         previous_stack,
-                                        obligations.into_iter(),
+                                        obligations,
                                     );
                                 }
                             }
@@ -964,8 +950,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                     match (evaluate(c1), evaluate(c2)) {
                         (Ok(c1), Ok(c2)) => {
-                            match self.infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2)
-                            {
+                            match self.infcx.at(&obligation.cause, obligation.param_env).eq(
+                                DefineOpaqueTypes::No,
+                                c1,
+                                c2,
+                            ) {
                                 Ok(inf_ok) => self.evaluate_predicates_recursively(
                                     previous_stack,
                                     inf_ok.into_obligations(),
@@ -993,7 +982,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
                 ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
                 ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
-                    match self.infcx.at(&obligation.cause, obligation.param_env).eq(ct.ty(), ty) {
+                    match self.infcx.at(&obligation.cause, obligation.param_env).eq(
+                        DefineOpaqueTypes::No,
+                        ct.ty(),
+                        ty,
+                    ) {
                         Ok(inf_ok) => self.evaluate_predicates_recursively(
                             previous_stack,
                             inf_ok.into_obligations(),
@@ -1358,24 +1351,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result);
     }
 
-    /// For various reasons, it's possible for a subobligation
-    /// to have a *lower* recursion_depth than the obligation used to create it.
-    /// Projection sub-obligations may be returned from the projection cache,
-    /// which results in obligations with an 'old' `recursion_depth`.
-    /// Additionally, methods like `InferCtxt.subtype_predicate` produce
-    /// subobligations without taking in a 'parent' depth, causing the
-    /// generated subobligations to have a `recursion_depth` of `0`.
-    ///
-    /// To ensure that obligation_depth never decreases, we force all subobligations
-    /// to have at least the depth of the original obligation.
-    fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>(
-        &self,
-        it: I,
-        min_depth: usize,
-    ) {
-        it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
-    }
-
     fn check_recursion_depth<T>(
         &self,
         depth: usize,
@@ -1751,7 +1726,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         });
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
+            .sup(DefineOpaqueTypes::No, ty::Binder::dummy(placeholder_trait_ref), trait_bound)
             .map(|InferOk { obligations: _, value: () }| {
                 // This method is called within a probe, so we can't have
                 // inference variables and placeholders escape.
@@ -1813,7 +1788,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let is_match = self
             .infcx
             .at(&obligation.cause, obligation.param_env)
-            .sup(obligation.predicate, infer_projection)
+            .sup(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
             .map_or(false, |InferOk { obligations, value: () }| {
                 self.evaluate_predicates_recursively(
                     TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
@@ -2432,15 +2407,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                             placeholder_ty,
                         )
                     });
-                let placeholder_obligation = predicate_for_trait_def(
+
+                let obligation = Obligation::new(
                     self.tcx(),
-                    param_env,
                     cause.clone(),
-                    trait_def_id,
-                    recursion_depth,
-                    [normalized_ty],
+                    param_env,
+                    self.tcx().mk_trait_ref(trait_def_id, [normalized_ty]),
                 );
-                obligations.push(placeholder_obligation);
+                obligations.push(obligation);
                 obligations
             })
             .collect()
@@ -2534,7 +2508,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         let InferOk { obligations, .. } = self
             .infcx
             .at(&cause, obligation.param_env)
-            .eq(placeholder_obligation_trait_ref, impl_trait_ref)
+            .eq(DefineOpaqueTypes::No, placeholder_obligation_trait_ref, impl_trait_ref)
             .map_err(|e| {
                 debug!("match_impl: failed eq_trait_refs due to `{}`", e.to_string(self.tcx()))
             })?;
@@ -2584,7 +2558,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
     ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
+            .sup(DefineOpaqueTypes::No, obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
             .map(|InferOk { obligations, .. }| obligations)
             .map_err(|_| ())
     }
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index fcfb60b2603..8546bbe52dc 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -10,6 +10,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
 
 pub mod specialization_graph;
+use rustc_infer::infer::DefineOpaqueTypes;
 use specialization_graph::GraphExt;
 
 use crate::errors::NegativePositiveConflict;
@@ -21,7 +22,7 @@ use crate::traits::{
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{error_code, DelayDm, Diagnostic};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt};
+use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
 use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
 use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
@@ -193,7 +194,7 @@ fn fulfill_implication<'tcx>(
 
     // do the impls unify? If not, no specialization.
     let Ok(InferOk { obligations: more_obligations, .. }) =
-        infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait, target_trait)
+        infcx.at(&ObligationCause::dummy(), param_env, ).eq(DefineOpaqueTypes::No,source_trait, target_trait)
     else {
         debug!(
             "fulfill_implication: {:?} does not unify with {:?}",
@@ -349,6 +350,10 @@ fn report_conflicting_impls<'tcx>(
         impl_span: Span,
         err: &mut Diagnostic,
     ) {
+        if (overlap.trait_ref, overlap.self_ty).references_error() {
+            err.downgrade_to_delayed_bug();
+        }
+
         match tcx.span_of_impl(overlap.with_impl) {
             Ok(span) => {
                 err.span_label(span, "first implementation here");
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index bcf63d5a6f6..00c9a352258 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -1,15 +1,14 @@
-use rustc_errors::Diagnostic;
-use rustc_span::Span;
-use smallvec::SmallVec;
-
+use super::NormalizeExt;
+use super::{ObligationCause, PredicateObligation, SelectionContext};
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Diagnostic;
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::InferOk;
+use rustc_middle::ty::SubstsRef;
 use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
-use rustc_middle::ty::{GenericArg, SubstsRef};
+use rustc_span::Span;
+use smallvec::SmallVec;
 
-use super::NormalizeExt;
-use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext};
-use rustc_infer::infer::InferOk;
 pub use rustc_infer::traits::{self, util::*};
 
 ///////////////////////////////////////////////////////////////////////////
@@ -201,6 +200,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
 ) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
     let subject = selcx.tcx().bound_impl_subject(impl_def_id);
     let subject = subject.subst(selcx.tcx(), impl_substs);
+
     let InferOk { value: subject, obligations: normalization_obligations1 } =
         selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(subject);
 
@@ -218,33 +218,6 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
     (subject, impl_obligations)
 }
 
-pub fn predicate_for_trait_ref<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    cause: ObligationCause<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    trait_ref: ty::TraitRef<'tcx>,
-    recursion_depth: usize,
-) -> PredicateObligation<'tcx> {
-    Obligation {
-        cause,
-        param_env,
-        recursion_depth,
-        predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
-    }
-}
-
-pub fn predicate_for_trait_def<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    cause: ObligationCause<'tcx>,
-    trait_def_id: DefId,
-    recursion_depth: usize,
-    params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
-) -> PredicateObligation<'tcx> {
-    let trait_ref = tcx.mk_trait_ref(trait_def_id, params);
-    predicate_for_trait_ref(tcx, cause, param_env, trait_ref, recursion_depth)
-}
-
 /// Casts a trait reference into a reference to one of its super
 /// traits; returns `None` if `target_trait_def_id` is not a
 /// supertrait.
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 867974749d5..6d9ad96fa74 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -11,20 +11,20 @@ pub fn provide(providers: &mut ty::query::Providers) {
         associated_item,
         associated_item_def_ids,
         associated_items,
-        associated_items_for_impl_trait_in_trait,
-        associated_item_for_impl_trait_in_trait,
+        associated_types_for_impl_traits_in_associated_fn,
+        associated_type_for_impl_trait_in_trait,
         impl_item_implementor_ids,
         ..*providers
     };
 }
 
-fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
-    let item = tcx.hir().expect_item(def_id.expect_local());
+fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] {
+    let item = tcx.hir().expect_item(def_id);
     match item.kind {
         hir::ItemKind::Trait(.., ref trait_item_refs) => {
             if tcx.lower_impl_trait_in_trait_to_assoc_ty() {
                 // We collect RPITITs for each trait method's return type and create a
-                // corresponding associated item using associated_items_for_impl_trait_in_trait
+                // corresponding associated item using associated_types_for_impl_traits_in_associated_fn
                 // query.
                 tcx.arena.alloc_from_iter(
                     trait_item_refs
@@ -39,7 +39,9 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
                                 .flat_map(|trait_item_ref| {
                                     let trait_fn_def_id =
                                         trait_item_ref.id.owner_id.def_id.to_def_id();
-                                    tcx.associated_items_for_impl_trait_in_trait(trait_fn_def_id)
+                                    tcx.associated_types_for_impl_traits_in_associated_fn(
+                                        trait_fn_def_id,
+                                    )
                                 })
                                 .map(|def_id| *def_id),
                         ),
@@ -56,7 +58,7 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
             if tcx.lower_impl_trait_in_trait_to_assoc_ty() {
                 // We collect RPITITs for each trait method's return type, on the impl side too and
                 // create a corresponding associated item using
-                // associated_items_for_impl_trait_in_trait query.
+                // associated_types_for_impl_traits_in_associated_fn query.
                 tcx.arena.alloc_from_iter(
                     impl_
                         .items
@@ -72,7 +74,9 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
                                 .flat_map(|impl_item_ref| {
                                     let impl_fn_def_id =
                                         impl_item_ref.id.owner_id.def_id.to_def_id();
-                                    tcx.associated_items_for_impl_trait_in_trait(impl_fn_def_id)
+                                    tcx.associated_types_for_impl_traits_in_associated_fn(
+                                        impl_fn_def_id,
+                                    )
                                 })
                                 .map(|def_id| *def_id)
                         })),
@@ -103,27 +107,26 @@ fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap<DefId>
         .collect()
 }
 
-fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
-    let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem {
+    let id = tcx.hir().local_def_id_to_hir_id(def_id);
     let parent_def_id = tcx.hir().get_parent_item(id);
     let parent_item = tcx.hir().expect_item(parent_def_id.def_id);
     match parent_item.kind {
         hir::ItemKind::Impl(ref impl_) => {
-            if let Some(impl_item_ref) =
-                impl_.items.iter().find(|i| i.id.owner_id.to_def_id() == def_id)
+            if let Some(impl_item_ref) = impl_.items.iter().find(|i| i.id.owner_id.def_id == def_id)
             {
                 let assoc_item = associated_item_from_impl_item_ref(impl_item_ref);
-                debug_assert_eq!(assoc_item.def_id, def_id);
+                debug_assert_eq!(assoc_item.def_id.expect_local(), def_id);
                 return assoc_item;
             }
         }
 
         hir::ItemKind::Trait(.., ref trait_item_refs) => {
             if let Some(trait_item_ref) =
-                trait_item_refs.iter().find(|i| i.id.owner_id.to_def_id() == def_id)
+                trait_item_refs.iter().find(|i| i.id.owner_id.def_id == def_id)
             {
                 let assoc_item = associated_item_from_trait_item_ref(trait_item_ref);
-                debug_assert_eq!(assoc_item.def_id, def_id);
+                debug_assert_eq!(assoc_item.def_id.expect_local(), def_id);
                 return assoc_item;
             }
         }
@@ -176,14 +179,20 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A
     }
 }
 
-/// Given an `fn_def_id` of a trait or of an impl that implements a given trait:
-/// if `fn_def_id` is the def id of a function defined inside a trait, then it creates and returns
-/// the associated items that correspond to each impl trait in return position for that trait.
-/// if `fn_def_id` is the def id of a function defined inside an impl that implements a trait, then it
-/// creates and returns the associated items that correspond to each impl trait in return position
-/// of the implemented trait.
-fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) -> &'_ [DefId] {
-    let parent_def_id = tcx.parent(fn_def_id);
+/// Given an `fn_def_id` of a trait or a trait implementation:
+///
+/// if `fn_def_id` is a function defined inside a trait, then it synthesizes
+/// a new def id corresponding to a new associated type for each return-
+/// position `impl Trait` in the signature.
+///
+/// if `fn_def_id` is a function inside of an impl, then for each synthetic
+/// associated type generated for the corresponding trait function described
+/// above, synthesize a corresponding associated type in the impl.
+fn associated_types_for_impl_traits_in_associated_fn(
+    tcx: TyCtxt<'_>,
+    fn_def_id: LocalDefId,
+) -> &'_ [DefId] {
+    let parent_def_id = tcx.local_parent(fn_def_id);
 
     match tcx.def_kind(parent_def_id) {
         DefKind::Trait => {
@@ -202,11 +211,11 @@ fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) -
 
             let mut visitor = RPITVisitor { rpits: Vec::new() };
 
-            if let Some(output) = tcx.hir().get_fn_output(fn_def_id.expect_local()) {
+            if let Some(output) = tcx.hir().get_fn_output(fn_def_id) {
                 visitor.visit_fn_ret_ty(output);
 
                 tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| {
-                    tcx.associated_item_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id()
+                    tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id()
                 }))
             } else {
                 &[]
@@ -217,12 +226,12 @@ fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) -
             let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else { return &[] };
 
             tcx.arena.alloc_from_iter(
-                tcx.associated_items_for_impl_trait_in_trait(trait_fn_def_id).iter().map(
+                tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map(
                     move |trait_assoc_def_id| {
-                        impl_associated_item_for_impl_trait_in_trait(
+                        associated_type_for_impl_trait_in_impl(
                             tcx,
                             trait_assoc_def_id.expect_local(),
-                            fn_def_id.expect_local(),
+                            fn_def_id,
                         )
                         .to_def_id()
                     },
@@ -231,20 +240,21 @@ fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) -
         }
 
         def_kind => bug!(
-            "associated_items_for_impl_trait_in_trait: {:?} should be Trait or Impl but is {:?}",
+            "associated_types_for_impl_traits_in_associated_fn: {:?} should be Trait or Impl but is {:?}",
             parent_def_id,
             def_kind
         ),
     }
 }
 
-/// Given an `opaque_ty_def_id` corresponding to an impl trait in trait, create and return the
-/// corresponding associated item.
-fn associated_item_for_impl_trait_in_trait(
+/// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated
+/// function from a trait, synthesize an associated type for that `impl Trait`
+/// that inherits properties that we infer from the method and the opaque type.
+fn associated_type_for_impl_trait_in_trait(
     tcx: TyCtxt<'_>,
     opaque_ty_def_id: LocalDefId,
 ) -> LocalDefId {
-    let fn_def_id = tcx.impl_trait_in_trait_parent(opaque_ty_def_id.to_def_id());
+    let fn_def_id = tcx.impl_trait_in_trait_parent_fn(opaque_ty_def_id.to_def_id());
     let trait_def_id = tcx.parent(fn_def_id);
     assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
 
@@ -286,11 +296,42 @@ fn associated_item_for_impl_trait_in_trait(
     // Copy type_of of the opaque.
     trait_assoc_ty.type_of(ty::EarlyBinder(tcx.mk_opaque(
         opaque_ty_def_id.to_def_id(),
-        InternalSubsts::identity_for_item(tcx, opaque_ty_def_id.to_def_id()),
+        InternalSubsts::identity_for_item(tcx, opaque_ty_def_id),
     )));
 
-    // Copy generics_of of the opaque.
-    trait_assoc_ty.generics_of(tcx.generics_of(opaque_ty_def_id).clone());
+    trait_assoc_ty.is_type_alias_impl_trait(false);
+
+    // Copy generics_of of the opaque type item but the trait is the parent.
+    trait_assoc_ty.generics_of({
+        let opaque_ty_generics = tcx.generics_of(opaque_ty_def_id);
+        let opaque_ty_parent_count = opaque_ty_generics.parent_count;
+        let mut params = opaque_ty_generics.params.clone();
+
+        let parent_generics = tcx.generics_of(trait_def_id);
+        let parent_count = parent_generics.parent_count + parent_generics.params.len();
+
+        let mut trait_fn_params = tcx.generics_of(fn_def_id).params.clone();
+
+        for param in &mut params {
+            param.index = param.index + parent_count as u32 + trait_fn_params.len() as u32
+                - opaque_ty_parent_count as u32;
+        }
+
+        trait_fn_params.extend(params);
+        params = trait_fn_params;
+
+        let param_def_id_to_index =
+            params.iter().map(|param| (param.def_id, param.index)).collect();
+
+        ty::Generics {
+            parent: Some(trait_def_id),
+            parent_count,
+            params,
+            param_def_id_to_index,
+            has_self: false,
+            has_late_bound_regions: opaque_ty_generics.has_late_bound_regions,
+        }
+    });
 
     // There are no predicates for the synthesized associated type.
     trait_assoc_ty.explicit_predicates_of(ty::GenericPredicates {
@@ -304,10 +345,12 @@ fn associated_item_for_impl_trait_in_trait(
     local_def_id
 }
 
-/// Given an `trait_assoc_def_id` that corresponds to a previously synthesized impl trait in trait
-/// into an associated type and an `impl_def_id` corresponding to an impl block, create and return
-/// the corresponding associated item inside the impl block.
-fn impl_associated_item_for_impl_trait_in_trait(
+/// Given an `trait_assoc_def_id` corresponding to an associated item synthesized
+/// from an `impl Trait` in an associated function from a trait, and an
+/// `impl_fn_def_id` that represents an implementation of the associated function
+/// that the `impl Trait` comes from, synthesize an associated type for that `impl Trait`
+/// that inherits properties that we infer from the method and the associated type.
+fn associated_type_for_impl_trait_in_impl(
     tcx: TyCtxt<'_>,
     trait_assoc_def_id: LocalDefId,
     impl_fn_def_id: LocalDefId,
@@ -328,6 +371,9 @@ fn impl_associated_item_for_impl_trait_in_trait(
     // `opt_local_def_id_to_hir_id` with `None`.
     impl_assoc_ty.opt_local_def_id_to_hir_id(None);
 
+    // Copy span of the opaque.
+    impl_assoc_ty.def_ident_span(Some(span));
+
     impl_assoc_ty.associated_item(ty::AssocItem {
         name: kw::Empty,
         kind: ty::AssocKind::Type,
@@ -342,10 +388,15 @@ fn impl_associated_item_for_impl_trait_in_trait(
     // extra predicates to assume.
     impl_assoc_ty.param_env(tcx.param_env(impl_fn_def_id));
 
+    // Copy visility of the containing function.
+    impl_assoc_ty.visibility(tcx.visibility(impl_fn_def_id));
+
     // Copy impl_defaultness of the containing function.
     impl_assoc_ty.impl_defaultness(tcx.impl_defaultness(impl_fn_def_id));
 
     // Copy generics_of the trait's associated item but the impl as the parent.
+    // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) resolves to the trait instead of the impl
+    // generics.
     impl_assoc_ty.generics_of({
         let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
         let trait_assoc_parent_count = trait_assoc_generics.parent_count;
@@ -354,16 +405,10 @@ fn impl_associated_item_for_impl_trait_in_trait(
         let parent_generics = tcx.generics_of(impl_def_id);
         let parent_count = parent_generics.parent_count + parent_generics.params.len();
 
-        let mut impl_fn_params = tcx.generics_of(impl_fn_def_id).params.clone();
-
         for param in &mut params {
-            param.index = param.index + parent_count as u32 + impl_fn_params.len() as u32
-                - trait_assoc_parent_count as u32;
+            param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32;
         }
 
-        impl_fn_params.extend(params);
-        params = impl_fn_params;
-
         let param_def_id_to_index =
             params.iter().map(|param| (param.def_id, param.index)).collect();
 
diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs
index d3169b6d962..3b1abdcb24f 100644
--- a/compiler/rustc_ty_utils/src/common_traits.rs
+++ b/compiler/rustc_ty_utils/src/common_traits.rs
@@ -3,7 +3,6 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits;
 
 fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
@@ -30,7 +29,7 @@ fn is_item_raw<'tcx>(
     let (param_env, ty) = query.into_parts();
     let trait_def_id = tcx.require_lang_item(item, None);
     let infcx = tcx.infer_ctxt().build();
-    traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id, DUMMY_SP)
+    traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id)
 }
 
 pub(crate) fn provide(providers: &mut ty::query::Providers) {
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index f2635271609..4d0fd260de2 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -425,7 +425,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
         destructure_const,
         thir_abstract_const: |tcx, def_id| {
-            let def_id = def_id.expect_local();
             if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
                 tcx.thir_abstract_const_of_const_arg(def)
             } else {
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index e3132fcc4c4..1788f544a7f 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -156,7 +156,11 @@ fn layout_of_uncached<'tcx>(
 
             let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
 
-            let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
+            let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type()
+                // Projection eagerly bails out when the pointee references errors,
+                // fall back to structurally deducing metadata.
+                && !pointee.references_error()
+            {
                 let metadata_ty = tcx.normalize_erasing_regions(
                     param_env,
                     tcx.mk_projection(metadata_def_id, [pointee]),
diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs
index 591017eecd2..26d6deab883 100644
--- a/compiler/rustc_ty_utils/src/representability.rs
+++ b/compiler/rustc_ty_utils/src/representability.rs
@@ -4,7 +4,7 @@ use rustc_hir::def::DefKind;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Representability, Ty, TyCtxt};
-use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::def_id::LocalDefId;
 
 pub fn provide(providers: &mut Providers) {
     *providers =
@@ -85,7 +85,7 @@ fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representab
     Representability::Representable
 }
 
-fn params_in_repr(tcx: TyCtxt<'_>, def_id: DefId) -> BitSet<u32> {
+fn params_in_repr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> BitSet<u32> {
     let adt_def = tcx.adt_def(def_id);
     let generics = tcx.generics_of(def_id);
     let mut params_in_repr = BitSet::new_empty(generics.params.len());
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index c8ed1f365f1..70686eefbca 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -7,7 +7,8 @@ use rustc_middle::ty::{
     TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use rustc_session::config::TraitSolver;
-use rustc_span::def_id::{DefId, CRATE_DEF_ID};
+use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits;
 
 fn sized_constraint_for_ty<'tcx>(
@@ -76,8 +77,8 @@ fn sized_constraint_for_ty<'tcx>(
     result
 }
 
-fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
-    match tcx.hir().get_by_def_id(def_id.expect_local()) {
+fn impl_defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
+    match tcx.hir().get_by_def_id(def_id) {
         hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.defaultness,
         hir::Node::ImplItem(hir::ImplItem { defaultness, .. })
         | hir::Node::TraitItem(hir::TraitItem { defaultness, .. }) => *defaultness,
@@ -117,19 +118,22 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {
 
 /// See `ParamEnv` struct definition for details.
 fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
-    // When computing the param_env of an RPITIT, copy param_env of the containing function. The
-    // synthesized associated type doesn't have extra predicates to assume.
-    let def_id =
-        if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) {
-            fn_def_id
-        } else {
-            def_id
-        };
-
     // Compute the bounds on Self and the type parameters.
     let ty::InstantiatedPredicates { mut predicates, .. } =
         tcx.predicates_of(def_id).instantiate_identity(tcx);
 
+    // When computing the param_env of an RPITIT, use predicates of the containing function,
+    // *except* for the additional assumption that the RPITIT normalizes to the trait method's
+    // default opaque type. This is needed to properly check the item bounds of the assoc
+    // type hold (`check_type_bounds`), since that method already installs a similar projection
+    // bound, so they will conflict.
+    // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): I don't like this, we should
+    // at least be making sure that the generics in RPITITs and their parent fn don't
+    // get out of alignment, or else we do actually need to substitute these predicates.
+    if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) {
+        predicates = tcx.predicates_of(fn_def_id).instantiate_identity(tcx).predicates;
+    }
+
     // Finally, we have to normalize the bounds in the environment, in
     // case they contain any associated type projections. This process
     // can yield errors if the put in illegal associated types, like
@@ -163,7 +167,9 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     }
 
     let local_did = def_id.as_local();
-    let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
+    // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): This isn't correct for
+    // RPITITs in const trait fn.
+    let hir_id = local_did.and_then(|def_id| tcx.opt_local_def_id_to_hir_id(def_id));
 
     // FIXME(consts): This is not exactly in line with the constness query.
     let constness = match hir_id {
@@ -270,33 +276,53 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
     }
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
-        if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
-            && self.tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder
-            && self.tcx.impl_trait_in_trait_parent(alias_ty.def_id) == self.fn_def_id
-            && self.seen.insert(alias_ty.def_id)
+        if let ty::Alias(ty::Projection, unshifted_alias_ty) = *ty.kind()
+            && self.tcx.is_impl_trait_in_trait(unshifted_alias_ty.def_id)
+            && self.tcx.impl_trait_in_trait_parent_fn(unshifted_alias_ty.def_id) == self.fn_def_id
+            && self.seen.insert(unshifted_alias_ty.def_id)
         {
             // We have entered some binders as we've walked into the
             // bounds of the RPITIT. Shift these binders back out when
             // constructing the top-level projection predicate.
-            let alias_ty = self.tcx.fold_regions(alias_ty, |re, _| {
+            let shifted_alias_ty = self.tcx.fold_regions(unshifted_alias_ty, |re, depth| {
                 if let ty::ReLateBound(index, bv) = re.kind() {
+                    if depth != ty::INNERMOST {
+                        return self.tcx.mk_re_error_with_message(
+                            DUMMY_SP,
+                            "we shouldn't walk non-predicate binders with `impl Trait`...",
+                        );
+                    }
                     self.tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv)
                 } else {
                     re
                 }
             });
+
+            // If we're lowering to associated item, install the opaque type which is just
+            // the `type_of` of the trait's associated item. If we're using the old lowering
+            // strategy, then just reinterpret the associated type like an opaque :^)
+            let default_ty = if self.tcx.lower_impl_trait_in_trait_to_assoc_ty() {
+                self.tcx.type_of(shifted_alias_ty.def_id).subst(self.tcx, shifted_alias_ty.substs)
+            } else {
+                self.tcx.mk_alias(ty::Opaque, shifted_alias_ty)
+            };
+
             self.predicates.push(
                 ty::Binder::bind_with_vars(
-                    ty::ProjectionPredicate {
-                        projection_ty: alias_ty,
-                        term: self.tcx.mk_alias(ty::Opaque, alias_ty).into(),
-                    },
+                    ty::ProjectionPredicate { projection_ty: shifted_alias_ty, term: default_ty.into() },
                     self.bound_vars,
                 )
                 .to_predicate(self.tcx),
             );
 
-            for bound in self.tcx.item_bounds(alias_ty.def_id).subst_iter(self.tcx, alias_ty.substs)
+            // We walk the *un-shifted* alias ty, because we're tracking the de bruijn
+            // binder depth, and if we were to walk `shifted_alias_ty` instead, we'd
+            // have to reset `self.depth` back to `ty::INNERMOST` or something. It's
+            // easier to just do this.
+            for bound in self
+                .tcx
+                .item_bounds(unshifted_alias_ty.def_id)
+                .subst_iter(self.tcx, unshifted_alias_ty.substs)
             {
                 bound.visit_with(self);
             }
@@ -488,8 +514,8 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<EarlyBinder<Ty<'
 }
 
 /// Check if a function is async.
-fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
-    let node = tcx.hir().get_by_def_id(def_id.expect_local());
+fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::IsAsync {
+    let node = tcx.hir().get_by_def_id(def_id);
     node.fn_sig().map_or(hir::IsAsync::NotAsync, |sig| sig.header.asyncness)
 }
 
diff --git a/config.example.toml b/config.example.toml
index dee0d8f254b..32eab76b369 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -146,6 +146,9 @@ changelog-seen = 2
 # Whether to build the clang compiler.
 #clang = false
 
+# Whether to enable llvm compilation warnings.
+#enable-warnings = false
+
 # Custom CMake defines to set when building LLVM.
 #build-config = {}
 
@@ -803,3 +806,9 @@ changelog-seen = 2
 #
 # This list must be non-empty.
 #compression-formats = ["gz", "xz"]
+
+# How much time should be spent compressing the tarballs. The better the
+# compression profile, the longer compression will take.
+#
+# Available options: fast, balanced, best
+#compression-profile = "fast"
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index e9cc3875f68..5469261ef56 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -87,7 +87,7 @@
 #![warn(missing_debug_implementations)]
 #![warn(missing_docs)]
 #![allow(explicit_outlives_requirements)]
-#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))]
+#![warn(multiple_supertrait_upcastable)]
 //
 // Library features:
 #![feature(alloc_layout_extra)]
@@ -195,7 +195,7 @@
 #![feature(c_unwind)]
 #![feature(with_negative_coherence)]
 #![cfg_attr(test, feature(panic_update_hook))]
-#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))]
+#![feature(multiple_supertrait_upcastable)]
 //
 // Rustdoc features:
 #![feature(doc_cfg)]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 77b0447b345..089b6b6418d 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -1738,11 +1738,11 @@ impl<T: ?Sized + PartialEq> PartialEq for Rc<T> {
 
     /// Inequality for two `Rc`s.
     ///
-    /// Two `Rc`s are unequal if their inner values are unequal.
+    /// Two `Rc`s are not equal if their inner values are not equal.
     ///
     /// If `T` also implements `Eq` (implying reflexivity of equality),
     /// two `Rc`s that point to the same allocation are
-    /// never unequal.
+    /// always equal.
     ///
     /// # Examples
     ///
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index f37573c6f27..8a27a7ecdf6 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -2475,10 +2475,10 @@ impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
 
     /// Inequality for two `Arc`s.
     ///
-    /// Two `Arc`s are unequal if their inner values are unequal.
+    /// Two `Arc`s are not equal if their inner values are not equal.
     ///
     /// If `T` also implements `Eq` (implying reflexivity of equality),
-    /// two `Arc`s that point to the same value are never unequal.
+    /// two `Arc`s that point to the same value are always equal.
     ///
     /// # Examples
     ///
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index f2aa30f18fc..9f0111db452 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -59,7 +59,6 @@ use core::cmp::Ordering;
 use core::convert::TryFrom;
 use core::fmt;
 use core::hash::{Hash, Hasher};
-use core::intrinsics::assume;
 use core::iter;
 #[cfg(not(no_global_oom_handling))]
 use core::iter::FromIterator;
@@ -1240,11 +1239,7 @@ impl<T, A: Allocator> Vec<T, A> {
     pub fn as_ptr(&self) -> *const T {
         // We shadow the slice method of the same name to avoid going through
         // `deref`, which creates an intermediate reference.
-        let ptr = self.buf.ptr();
-        unsafe {
-            assume(!ptr.is_null());
-        }
-        ptr
+        self.buf.ptr()
     }
 
     /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling
@@ -1277,11 +1272,7 @@ impl<T, A: Allocator> Vec<T, A> {
     pub fn as_mut_ptr(&mut self) -> *mut T {
         // We shadow the slice method of the same name to avoid going through
         // `deref_mut`, which creates an intermediate reference.
-        let ptr = self.buf.ptr();
-        unsafe {
-            assume(!ptr.is_null());
-        }
-        ptr
+        self.buf.ptr()
     }
 
     /// Returns a reference to the underlying allocator.
diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs
index 4d182be02c9..c1dbbde08b6 100644
--- a/library/alloc/tests/str.rs
+++ b/library/alloc/tests/str.rs
@@ -1499,13 +1499,25 @@ fn test_split_whitespace() {
 
 #[test]
 fn test_lines() {
-    let data = "\nMäry häd ä little lämb\n\r\nLittle lämb\n";
-    let lines: Vec<&str> = data.lines().collect();
-    assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]);
-
-    let data = "\r\nMäry häd ä little lämb\n\nLittle lämb"; // no trailing \n
-    let lines: Vec<&str> = data.lines().collect();
-    assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]);
+    fn t(data: &str, expected: &[&str]) {
+        let lines: Vec<&str> = data.lines().collect();
+        assert_eq!(lines, expected);
+    }
+    t("", &[]);
+    t("\n", &[""]);
+    t("\n2nd", &["", "2nd"]);
+    t("\r\n", &[""]);
+    t("bare\r", &["bare\r"]);
+    t("bare\rcr", &["bare\rcr"]);
+    t("Text\n\r", &["Text", "\r"]);
+    t(
+        "\nMäry häd ä little lämb\n\r\nLittle lämb\n",
+        &["", "Märy häd ä little lämb", "", "Little lämb"],
+    );
+    t(
+        "\r\nMäry häd ä little lämb\n\nLittle lämb",
+        &["", "Märy häd ä little lämb", "", "Little lämb"],
+    );
 }
 
 #[test]
diff --git a/library/core/src/error.rs b/library/core/src/error.rs
index 571bc4bcfd1..11cb0827578 100644
--- a/library/core/src/error.rs
+++ b/library/core/src/error.rs
@@ -28,7 +28,7 @@ use crate::fmt::{Debug, Display};
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
 #[rustc_has_incoherent_inherent_impls]
-#[cfg_attr(not(bootstrap), allow(multiple_supertrait_upcastable))]
+#[allow(multiple_supertrait_upcastable)]
 pub trait Error: Debug + Display {
     /// The lower-level source of this error, if any.
     ///
@@ -489,7 +489,7 @@ impl Error for crate::char::CharTryFromError {
 #[stable(feature = "duration_checked_float", since = "1.66.0")]
 impl Error for crate::time::TryFromFloatSecsError {}
 
-#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
 impl Error for crate::ffi::FromBytesUntilNulError {}
 
 #[unstable(feature = "get_many_mut", issue = "104642")]
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 87f077325f8..fe8abdf7fad 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -153,10 +153,10 @@ impl Error for FromBytesWithNulError {
 /// This error is created by the [`CStr::from_bytes_until_nul`] method.
 ///
 #[derive(Clone, PartialEq, Eq, Debug)]
-#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
 pub struct FromBytesUntilNulError(());
 
-#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
 impl fmt::Display for FromBytesUntilNulError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "data provided does not contain a nul")
@@ -324,8 +324,8 @@ impl CStr {
     /// ```
     ///
     #[rustc_allow_const_fn_unstable(const_slice_index)]
-    #[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
-    #[rustc_const_stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
+    #[rustc_const_stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
     pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
         let nul_pos = memchr::memchr(0, bytes);
         match nul_pos {
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index c9821bf8109..fcda097f01f 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -267,7 +267,7 @@ extern "C" {
 /// family of functions. It contains a function to format the given value. At
 /// compile time it is ensured that the function and the value have the correct
 /// types, and then this struct is used to canonicalize arguments to one type.
-#[cfg_attr(not(bootstrap), lang = "format_argument")]
+#[lang = "format_argument"]
 #[derive(Copy, Clone)]
 #[allow(missing_debug_implementations)]
 #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
@@ -280,7 +280,7 @@ pub struct ArgumentV1<'a> {
 /// This struct represents the unsafety of constructing an `Arguments`.
 /// It exists, rather than an unsafe function, in order to simplify the expansion
 /// of `format_args!(..)` and reduce the scope of the `unsafe` block.
-#[cfg_attr(not(bootstrap), lang = "format_unsafe_arg")]
+#[lang = "format_unsafe_arg"]
 #[allow(missing_debug_implementations)]
 #[doc(hidden)]
 #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
@@ -392,8 +392,31 @@ enum FlagV1 {
 }
 
 impl<'a> Arguments<'a> {
+    #[doc(hidden)]
+    #[inline]
+    #[unstable(feature = "fmt_internals", issue = "none")]
+    #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
+    pub const fn new_const(pieces: &'a [&'static str]) -> Self {
+        if pieces.len() > 1 {
+            panic!("invalid args");
+        }
+        Arguments { pieces, fmt: None, args: &[] }
+    }
+
     /// When using the format_args!() macro, this function is used to generate the
     /// Arguments structure.
+    #[cfg(not(bootstrap))]
+    #[doc(hidden)]
+    #[inline]
+    #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
+    pub fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
+        if pieces.len() < args.len() || pieces.len() > args.len() + 1 {
+            panic!("invalid args");
+        }
+        Arguments { pieces, fmt: None, args }
+    }
+
+    #[cfg(bootstrap)]
     #[doc(hidden)]
     #[inline]
     #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
@@ -417,8 +440,7 @@ impl<'a> Arguments<'a> {
     #[doc(hidden)]
     #[inline]
     #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
-    #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
-    pub const fn new_v1_formatted(
+    pub fn new_v1_formatted(
         pieces: &'a [&'static str],
         args: &'a [ArgumentV1<'a>],
         fmt: &'a [rt::v1::Argument],
@@ -475,7 +497,7 @@ impl<'a> Arguments<'a> {
 /// ```
 ///
 /// [`format()`]: ../../std/fmt/fn.format.html
-#[cfg_attr(not(bootstrap), lang = "format_arguments")]
+#[lang = "format_arguments"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Copy, Clone)]
 pub struct Arguments<'a> {
diff --git a/library/core/src/fmt/rt/v1.rs b/library/core/src/fmt/rt/v1.rs
index 11a50951a75..6d70796f707 100644
--- a/library/core/src/fmt/rt/v1.rs
+++ b/library/core/src/fmt/rt/v1.rs
@@ -5,7 +5,7 @@
 //! these can be statically allocated and are slightly optimized for the runtime
 #![allow(missing_debug_implementations)]
 
-#[cfg_attr(not(bootstrap), lang = "format_placeholder")]
+#[lang = "format_placeholder"]
 #[derive(Copy, Clone)]
 // FIXME: Rename this to Placeholder
 pub struct Argument {
@@ -37,7 +37,7 @@ impl Argument {
 }
 
 /// Possible alignments that can be requested as part of a formatting directive.
-#[cfg_attr(not(bootstrap), lang = "format_alignment")]
+#[lang = "format_alignment"]
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum Alignment {
     /// Indication that contents should be left-aligned.
@@ -51,7 +51,7 @@ pub enum Alignment {
 }
 
 /// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
-#[cfg_attr(not(bootstrap), lang = "format_count")]
+#[lang = "format_count"]
 #[derive(Copy, Clone)]
 pub enum Count {
     /// Specified with a literal number, stores the value
diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs
index 46cbcd43530..04f02d47f92 100644
--- a/library/core/src/future/mod.rs
+++ b/library/core/src/future/mod.rs
@@ -67,14 +67,10 @@ pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
     unsafe { &mut *cx.0.as_ptr().cast() }
 }
 
-// FIXME(swatinem): This fn is currently needed to work around shortcomings
-// in type and lifetime inference.
-// See the comment at the bottom of `LoweringContext::make_async_expr` and
-// <https://github.com/rust-lang/rust/issues/104826>.
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[inline]
-#[lang = "identity_future"]
+#[cfg_attr(bootstrap, lang = "identity_future")]
 pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
     f
 }
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index 71a0d1825ef..4e7bae7bcb0 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -158,7 +158,7 @@ mod sip;
 ///
 /// Implementations of `hash` should ensure that the data they
 /// pass to the `Hasher` are prefix-free. That is,
-/// unequal values should cause two different sequences of values to be written,
+/// values which are not equal should cause two different sequences of values to be written,
 /// and neither of the two sequences should be a prefix of the other.
 ///
 /// For example, the standard implementation of [`Hash` for `&str`][impl] passes an extra
@@ -834,7 +834,7 @@ mod impls {
 
                 #[inline]
                 fn hash_slice<H: ~const Hasher>(data: &[$ty], state: &mut H) {
-                    let newlen = data.len() * mem::size_of::<$ty>();
+                    let newlen = mem::size_of_val(data);
                     let ptr = data.as_ptr() as *const u8;
                     // SAFETY: `ptr` is valid and aligned, as this macro is only used
                     // for numeric primitives which have no padding. The new slice only
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index c6321587adc..7482b8b0862 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2020,6 +2020,16 @@ extern "rust-intrinsic" {
     #[rustc_safe_intrinsic]
     pub fn saturating_sub<T: Copy>(a: T, b: T) -> T;
 
+    /// This is an implementation detail of [`crate::ptr::read`] and should
+    /// not be used anywhere else.  See its comments for why this exists.
+    ///
+    /// This intrinsic can *only* be called where the argument is a local without
+    /// projections (`read_via_copy(p)`, not `read_via_copy(*p)`) so that it
+    /// trivially obeys runtime-MIR rules about derefs in operands.
+    #[cfg(not(bootstrap))]
+    #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+    pub fn read_via_copy<T>(p: *const T) -> T;
+
     /// Returns the value of the discriminant for the variant in 'v';
     /// if `T` has no discriminant, returns `0`.
     ///
@@ -2204,6 +2214,12 @@ extern "rust-intrinsic" {
     where
         G: FnOnce<ARG, Output = RET>,
         F: FnOnce<ARG, Output = RET>;
+
+    #[cfg(not(bootstrap))]
+    /// This method creates a pointer to any `Some` value. If the argument is
+    /// `None`, an invalid within-bounds pointer (that is still acceptable for
+    /// constructing an empty slice) is returned.
+    pub fn option_payload_ptr<T>(arg: *const Option<T>) -> *const T;
 }
 
 // Some functions are defined here because they accidentally got made
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index d2d9771bdce..64fc1c0c277 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -8,7 +8,7 @@
 //!
 //! The documentation for this module describes how to use this feature. If you are interested in
 //! hacking on the implementation, most of that documentation lives at
-//! `rustc_mir_building/src/build/custom/mod.rs`.
+//! `rustc_mir_build/src/build/custom/mod.rs`.
 //!
 //! Typical usage will look like this:
 //!
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index ae00232c12c..de638552fa3 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -278,7 +278,7 @@
 //!
 //! ```
 //! # #![allow(unused_must_use)]
-//! # #![cfg_attr(not(bootstrap), allow(map_unit_fn))]
+//! # #![allow(map_unit_fn)]
 //! let v = vec![1, 2, 3, 4, 5];
 //! v.iter().map(|x| println!("{x}"));
 //! ```
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index 78e27d73065..f19636fba5d 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -1,4 +1,5 @@
 use crate::convert::TryFrom;
+use crate::marker::Destruct;
 use crate::mem;
 use crate::ops::{self, Try};
 
@@ -20,7 +21,8 @@ unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usi
 /// The *successor* operation moves towards values that compare greater.
 /// The *predecessor* operation moves towards values that compare lesser.
 #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-pub trait Step: Clone + PartialOrd + Sized {
+#[const_trait]
+pub trait Step: ~const Clone + ~const PartialOrd + Sized {
     /// Returns the number of *successor* steps required to get from `start` to `end`.
     ///
     /// Returns `None` if the number of steps would overflow `usize`
@@ -234,7 +236,8 @@ macro_rules! step_integer_impls {
         $(
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            impl Step for $u_narrower {
+            #[rustc_const_unstable(feature = "const_iter", issue = "92476")]
+            impl const Step for $u_narrower {
                 step_identical_methods!();
 
                 #[inline]
@@ -266,7 +269,8 @@ macro_rules! step_integer_impls {
 
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            impl Step for $i_narrower {
+            #[rustc_const_unstable(feature = "const_iter", issue = "92476")]
+            impl const Step for $i_narrower {
                 step_identical_methods!();
 
                 #[inline]
@@ -330,7 +334,8 @@ macro_rules! step_integer_impls {
         $(
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            impl Step for $u_wider {
+            #[rustc_const_unstable(feature = "const_iter", issue = "92476")]
+            impl const Step for $u_wider {
                 step_identical_methods!();
 
                 #[inline]
@@ -355,7 +360,8 @@ macro_rules! step_integer_impls {
 
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            impl Step for $i_wider {
+            #[rustc_const_unstable(feature = "const_iter", issue = "92476")]
+            impl const Step for $i_wider {
                 step_identical_methods!();
 
                 #[inline]
@@ -405,7 +411,8 @@ step_integer_impls! {
 }
 
 #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-impl Step for char {
+#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
+impl const Step for char {
     #[inline]
     fn steps_between(&start: &char, &end: &char) -> Option<usize> {
         let start = start as u32;
@@ -423,6 +430,7 @@ impl Step for char {
     }
 
     #[inline]
+    #[rustc_allow_const_fn_unstable(const_try)]
     fn forward_checked(start: char, count: usize) -> Option<char> {
         let start = start as u32;
         let mut res = Step::forward_checked(start, count)?;
@@ -439,6 +447,7 @@ impl Step for char {
     }
 
     #[inline]
+    #[rustc_allow_const_fn_unstable(const_try)]
     fn backward_checked(start: char, count: usize) -> Option<char> {
         let start = start as u32;
         let mut res = Step::backward_checked(start, count)?;
@@ -514,6 +523,7 @@ macro_rules! range_incl_exact_iter_impl {
 }
 
 /// Specialization implementations for `Range`.
+#[const_trait]
 trait RangeIteratorImpl {
     type Item;
 
@@ -528,7 +538,7 @@ trait RangeIteratorImpl {
     fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize>;
 }
 
-impl<A: Step> RangeIteratorImpl for ops::Range<A> {
+impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A> {
     type Item = A;
 
     #[inline]
@@ -614,7 +624,7 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
     }
 }
 
-impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
+impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::Range<T> {
     #[inline]
     fn spec_next(&mut self) -> Option<T> {
         if self.start < self.end {
@@ -702,7 +712,8 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<A: Step> Iterator for ops::Range<A> {
+#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
+impl<A: ~const Step + ~const Destruct> const Iterator for ops::Range<A> {
     type Item = A;
 
     #[inline]
@@ -812,7 +823,8 @@ range_incl_exact_iter_impl! {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<A: Step> DoubleEndedIterator for ops::Range<A> {
+#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
+impl<A: ~const Step + ~const Destruct> const DoubleEndedIterator for ops::Range<A> {
     #[inline]
     fn next_back(&mut self) -> Option<A> {
         self.spec_next_back()
diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs
index e31669b3924..f9c7eb8f938 100644
--- a/library/core/src/iter/traits/accum.rs
+++ b/library/core/src/iter/traits/accum.rs
@@ -164,12 +164,13 @@ where
     /// element is encountered:
     ///
     /// ```
+    /// let f = |&x: &i32| if x < 0 { Err("Negative element found") } else { Ok(x) };
     /// let v = vec![1, 2];
-    /// let res: Result<i32, &'static str> = v.iter().map(|&x: &i32|
-    ///     if x < 0 { Err("Negative element found") }
-    ///     else { Ok(x) }
-    /// ).sum();
+    /// let res: Result<i32, _> = v.iter().map(f).sum();
     /// assert_eq!(res, Ok(3));
+    /// let v = vec![1, -2];
+    /// let res: Result<i32, _> = v.iter().map(f).sum();
+    /// assert_eq!(res, Err("Negative element found"));
     /// ```
     fn sum<I>(iter: I) -> Result<T, E>
     where
@@ -187,6 +188,20 @@ where
     /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
     /// elements are taken, and the [`Err`] is returned. Should no [`Err`]
     /// occur, the product of all elements is returned.
+    ///
+    /// # Examples
+    ///
+    /// This multiplies each number in a vector of strings,
+    /// if a string could not be parsed the operation returns `Err`:
+    ///
+    /// ```
+    /// let nums = vec!["5", "10", "1", "2"];
+    /// let total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();
+    /// assert_eq!(total, Ok(100));
+    /// let nums = vec!["5", "10", "one", "2"];
+    /// let total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();
+    /// assert!(total.is_err());
+    /// ```
     fn product<I>(iter: I) -> Result<T, E>
     where
         I: Iterator<Item = Result<U, E>>,
@@ -213,6 +228,9 @@ where
     /// let words = vec!["have", "a", "great", "day"];
     /// let total: Option<usize> = words.iter().map(|w| w.find('a')).sum();
     /// assert_eq!(total, Some(5));
+    /// let words = vec!["have", "a", "good", "day"];
+    /// let total: Option<usize> = words.iter().map(|w| w.find('a')).sum();
+    /// assert_eq!(total, None);
     /// ```
     fn sum<I>(iter: I) -> Option<T>
     where
@@ -230,6 +248,20 @@ where
     /// Takes each element in the [`Iterator`]: if it is a [`None`], no further
     /// elements are taken, and the [`None`] is returned. Should no [`None`]
     /// occur, the product of all elements is returned.
+    ///
+    /// # Examples
+    ///
+    /// This multiplies each number in a vector of strings,
+    /// if a string could not be parsed the operation returns `None`:
+    ///
+    /// ```
+    /// let nums = vec!["5", "10", "1", "2"];
+    /// let total: Option<usize> = nums.iter().map(|w| w.parse::<usize>().ok()).product();
+    /// assert_eq!(total, Some(100));
+    /// let nums = vec!["5", "10", "one", "2"];
+    /// let total: Option<usize> = nums.iter().map(|w| w.parse::<usize>().ok()).product();
+    /// assert_eq!(total, None);
+    /// ```
     fn product<I>(iter: I) -> Option<T>
     where
         I: Iterator<Item = Option<U>>,
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index ed23873cdde..7a10dea500a 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -1,3 +1,4 @@
+use crate::marker::Destruct;
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator able to yield elements from both ends.
@@ -37,6 +38,7 @@ use crate::ops::{ControlFlow, Try};
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "DoubleEndedIterator")]
+#[const_trait]
 pub trait DoubleEndedIterator: Iterator {
     /// Removes and returns an element from the end of the iterator.
     ///
@@ -131,7 +133,10 @@ pub trait DoubleEndedIterator: Iterator {
     /// [`Err(k)`]: Err
     #[inline]
     #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), usize>
+    where
+        Self::Item: ~const Destruct,
+    {
         for i in 0..n {
             self.next_back().ok_or(i)?;
         }
@@ -181,6 +186,7 @@ pub trait DoubleEndedIterator: Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iter_nth_back", since = "1.37.0")]
+    #[rustc_do_not_const_check]
     fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
         self.advance_back_by(n).ok()?;
         self.next_back()
@@ -218,6 +224,7 @@ pub trait DoubleEndedIterator: Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iterator_try_fold", since = "1.27.0")]
+    #[rustc_do_not_const_check]
     fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
     where
         Self: Sized,
@@ -289,6 +296,7 @@ pub trait DoubleEndedIterator: Iterator {
     #[doc(alias = "foldr")]
     #[inline]
     #[stable(feature = "iter_rfold", since = "1.27.0")]
+    #[rustc_do_not_const_check]
     fn rfold<B, F>(mut self, init: B, mut f: F) -> B
     where
         Self: Sized,
@@ -344,6 +352,7 @@ pub trait DoubleEndedIterator: Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iter_rfind", since = "1.27.0")]
+    #[rustc_do_not_const_check]
     fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
     where
         Self: Sized,
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index b8e7d0a68da..16c9f668b8e 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -1,5 +1,6 @@
 use crate::array;
 use crate::cmp::{self, Ordering};
+use crate::marker::Destruct;
 use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
 
 use super::super::try_process;
@@ -69,7 +70,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
 #[doc(notable_trait)]
 #[rustc_diagnostic_item = "Iterator"]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
-#[cfg_attr(not(bootstrap), const_trait)]
+#[const_trait]
 pub trait Iterator {
     /// The type of the elements being iterated over.
     #[rustc_diagnostic_item = "IteratorItem"]
@@ -336,8 +337,10 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
-    #[rustc_do_not_const_check]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), usize>
+    where
+        Self::Item: ~const Destruct,
+    {
         for i in 0..n {
             self.next().ok_or(i)?;
         }
@@ -385,8 +388,10 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_do_not_const_check]
-    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+    fn nth(&mut self, n: usize) -> Option<Self::Item>
+    where
+        Self::Item: ~const Destruct,
+    {
         self.advance_by(n).ok()?;
         self.next()
     }
@@ -1998,7 +2003,7 @@ pub trait Iterator {
     /// a.iter().map(|&x| x * 2).collect_into(&mut vec);
     /// a.iter().map(|&x| x * 10).collect_into(&mut vec);
     ///
-    /// assert_eq!(vec![0, 1, 2, 4, 6, 10, 20, 30], vec);
+    /// assert_eq!(vec, vec![0, 1, 2, 4, 6, 10, 20, 30]);
     /// ```
     ///
     /// `Vec` can have a manual set capacity to avoid reallocating it:
@@ -2013,7 +2018,7 @@ pub trait Iterator {
     /// a.iter().map(|&x| x * 10).collect_into(&mut vec);
     ///
     /// assert_eq!(6, vec.capacity());
-    /// println!("{:?}", vec);
+    /// assert_eq!(vec, vec![2, 4, 6, 10, 20, 30]);
     /// ```
     ///
     /// The returned mutable reference can be used to continue the call chain:
@@ -2027,12 +2032,12 @@ pub trait Iterator {
     /// let count = a.iter().collect_into(&mut vec).iter().count();
     ///
     /// assert_eq!(count, vec.len());
-    /// println!("Vec len is {}", count);
+    /// assert_eq!(vec, vec![1, 2, 3]);
     ///
     /// let count = a.iter().collect_into(&mut vec).iter().count();
     ///
     /// assert_eq!(count, vec.len());
-    /// println!("Vec len now is {}", count);
+    /// assert_eq!(vec, vec![1, 2, 3, 1, 2, 3]);
     /// ```
     #[inline]
     #[unstable(feature = "iter_collect_into", reason = "new API", issue = "94780")]
@@ -3443,6 +3448,9 @@ pub trait Iterator {
     ///
     /// An empty iterator returns the zero value of the type.
     ///
+    /// `sum()` can be used to sum any type implementing [`Sum`][`core::iter::Sum`],
+    /// including [`Option`][`Option::sum`] and [`Result`][`Result::sum`].
+    ///
     /// # Panics
     ///
     /// When calling `sum()` and a primitive integer type is being returned, this
@@ -3473,6 +3481,9 @@ pub trait Iterator {
     ///
     /// An empty iterator returns the one value of the type.
     ///
+    /// `product()` can be used to multiply any type implementing [`Product`][`core::iter::Product`],
+    /// including [`Option`][`Option::product`] and [`Result`][`Result::product`].
+    ///
     /// # Panics
     ///
     /// When calling `product()` and a primitive integer type is being returned,
@@ -3721,7 +3732,7 @@ pub trait Iterator {
         }
     }
 
-    /// Determines if the elements of this [`Iterator`] are unequal to those of
+    /// Determines if the elements of this [`Iterator`] are not equal to those of
     /// another.
     ///
     /// # Examples
diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs
index af02848233d..c8f60defff7 100644
--- a/library/core/src/iter/traits/marker.rs
+++ b/library/core/src/iter/traits/marker.rs
@@ -86,4 +86,5 @@ pub unsafe trait InPlaceIterable: Iterator {}
 /// for details. Consumers are free to rely on the invariants in unsafe code.
 #[unstable(feature = "trusted_step", issue = "85731")]
 #[rustc_specialization_trait]
-pub unsafe trait TrustedStep: Step {}
+#[const_trait]
+pub unsafe trait TrustedStep: ~const Step {}
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 24bad799fc8..1076d357070 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -95,7 +95,7 @@
 #![warn(missing_docs)]
 #![allow(explicit_outlives_requirements)]
 #![allow(incomplete_features)]
-#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))]
+#![warn(multiple_supertrait_upcastable)]
 //
 // Library features:
 #![feature(const_align_offset)]
@@ -123,9 +123,11 @@
 #![feature(const_index_range_slice_index)]
 #![feature(const_inherent_unchecked_arith)]
 #![feature(const_int_unchecked_arith)]
+#![feature(const_intoiterator_identity)]
 #![feature(const_intrinsic_forget)]
 #![feature(const_ipv4)]
 #![feature(const_ipv6)]
+#![feature(const_iter)]
 #![feature(const_likely)]
 #![feature(const_maybe_uninit_uninit_array)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
@@ -241,7 +243,7 @@
 #![feature(unsized_fn_params)]
 #![feature(asm_const)]
 #![feature(const_transmute_copy)]
-#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))]
+#![feature(multiple_supertrait_upcastable)]
 //
 // Target features:
 #![feature(arm_target_feature)]
@@ -254,7 +256,6 @@
 #![feature(sse4a_target_feature)]
 #![feature(tbm_target_feature)]
 #![feature(wasm_target_feature)]
-#![cfg_attr(bootstrap, feature(cmpxchg16b_target_feature))]
 
 // allow using `core::` in intra-doc links
 #[allow(unused_extern_crates)]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 3b026bc0e0f..529f62f4d6c 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -340,9 +340,9 @@ pub macro debug_assert_matches($($arg:tt)*) {
 #[stable(feature = "matches_macro", since = "1.42.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "matches_macro")]
 macro_rules! matches {
-    ($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
+    ($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => {
         match $expression {
-            $( $pattern )|+ $( if $guard )? => true,
+            $pattern $(if $guard)? => true,
             _ => false
         }
     };
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 427146941ad..9a0fd1f5f51 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -97,7 +97,7 @@ unsafe impl<T: Sync + ?Sized> Send for &T {}
 #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
 #[rustc_specialization_trait]
 #[rustc_deny_explicit_impl]
-#[cfg_attr(not(bootstrap), rustc_coinductive)]
+#[rustc_coinductive]
 pub trait Sized {
     // Empty.
 }
@@ -877,8 +877,7 @@ pub trait Tuple {}
 /// All types that have the same size and alignment as a `usize` or
 /// `*const ()` automatically implement this trait.
 #[unstable(feature = "pointer_like_trait", issue = "none")]
-#[cfg_attr(bootstrap, lang = "pointer_sized")]
-#[cfg_attr(not(bootstrap), lang = "pointer_like")]
+#[lang = "pointer_like"]
 #[rustc_on_unimplemented(
     message = "`{Self}` needs to have the same alignment and size as a pointer",
     label = "`{Self}` needs to be a pointer-like type"
diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs
index 0d25ab1d5e1..2d48e271580 100644
--- a/library/core/src/net/socket_addr.rs
+++ b/library/core/src/net/socket_addr.rs
@@ -121,7 +121,7 @@ impl SocketAddr {
     /// ```
     #[stable(feature = "ip_addr", since = "1.7.0")]
     #[must_use]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn new(ip: IpAddr, port: u16) -> SocketAddr {
         match ip {
             IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
@@ -141,7 +141,7 @@ impl SocketAddr {
     /// ```
     #[must_use]
     #[stable(feature = "ip_addr", since = "1.7.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn ip(&self) -> IpAddr {
         match *self {
             SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
@@ -182,7 +182,7 @@ impl SocketAddr {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn port(&self) -> u16 {
         match *self {
             SocketAddr::V4(ref a) => a.port(),
@@ -226,7 +226,7 @@ impl SocketAddr {
     /// ```
     #[must_use]
     #[stable(feature = "sockaddr_checker", since = "1.16.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn is_ipv4(&self) -> bool {
         matches!(*self, SocketAddr::V4(_))
     }
@@ -248,7 +248,7 @@ impl SocketAddr {
     /// ```
     #[must_use]
     #[stable(feature = "sockaddr_checker", since = "1.16.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn is_ipv6(&self) -> bool {
         matches!(*self, SocketAddr::V6(_))
     }
@@ -268,7 +268,7 @@ impl SocketAddrV4 {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
         SocketAddrV4 { ip, port }
     }
@@ -285,7 +285,7 @@ impl SocketAddrV4 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn ip(&self) -> &Ipv4Addr {
         &self.ip
     }
@@ -318,7 +318,7 @@ impl SocketAddrV4 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn port(&self) -> u16 {
         self.port
     }
@@ -359,7 +359,7 @@ impl SocketAddrV6 {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 {
         SocketAddrV6 { ip, port, flowinfo, scope_id }
     }
@@ -376,7 +376,7 @@ impl SocketAddrV6 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn ip(&self) -> &Ipv6Addr {
         &self.ip
     }
@@ -409,7 +409,7 @@ impl SocketAddrV6 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn port(&self) -> u16 {
         self.port
     }
@@ -452,7 +452,7 @@ impl SocketAddrV6 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn flowinfo(&self) -> u32 {
         self.flowinfo
     }
@@ -492,7 +492,7 @@ impl SocketAddrV6 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
     pub const fn scope_id(&self) -> u32 {
         self.scope_id
     }
diff --git a/library/core/src/num/dec2flt/common.rs b/library/core/src/num/dec2flt/common.rs
index 17957d7e770..3e8d75df378 100644
--- a/library/core/src/num/dec2flt/common.rs
+++ b/library/core/src/num/dec2flt/common.rs
@@ -192,6 +192,7 @@ pub struct BiasedFp {
 }
 
 impl BiasedFp {
+    #[inline]
     pub const fn zero_pow2(e: i32) -> Self {
         Self { f: 0, e }
     }
diff --git a/library/core/src/num/dec2flt/float.rs b/library/core/src/num/dec2flt/float.rs
index 5921c5ed472..1c9d68999d6 100644
--- a/library/core/src/num/dec2flt/float.rs
+++ b/library/core/src/num/dec2flt/float.rs
@@ -118,11 +118,13 @@ impl RawFloat for f32 {
     const SMALLEST_POWER_OF_TEN: i32 = -65;
     const LARGEST_POWER_OF_TEN: i32 = 38;
 
+    #[inline]
     fn from_u64(v: u64) -> Self {
         debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
         v as _
     }
 
+    #[inline]
     fn from_u64_bits(v: u64) -> Self {
         f32::from_bits((v & 0xFFFFFFFF) as u32)
     }
@@ -169,11 +171,13 @@ impl RawFloat for f64 {
     const SMALLEST_POWER_OF_TEN: i32 = -342;
     const LARGEST_POWER_OF_TEN: i32 = 308;
 
+    #[inline]
     fn from_u64(v: u64) -> Self {
         debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
         v as _
     }
 
+    #[inline]
     fn from_u64_bits(v: u64) -> Self {
         f64::from_bits(v)
     }
diff --git a/library/core/src/num/dec2flt/lemire.rs b/library/core/src/num/dec2flt/lemire.rs
index 9f7594460a1..3bc052df7a6 100644
--- a/library/core/src/num/dec2flt/lemire.rs
+++ b/library/core/src/num/dec2flt/lemire.rs
@@ -118,10 +118,12 @@ pub fn compute_float<F: RawFloat>(q: i64, mut w: u64) -> BiasedFp {
 /// This uses a pre-computed integer approximation for
 /// log2(10), where 217706 / 2^16 is accurate for the
 /// entire range of non-finite decimal exponents.
+#[inline]
 fn power(q: i32) -> i32 {
     (q.wrapping_mul(152_170 + 65536) >> 16) + 63
 }
 
+#[inline]
 fn full_multiplication(a: u64, b: u64) -> (u64, u64) {
     let r = (a as u128) * (b as u128);
     (r as u64, (r >> 64) as u64)
diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs
index f8d493e8b62..58ffb950ad8 100644
--- a/library/core/src/num/dec2flt/mod.rs
+++ b/library/core/src/num/dec2flt/mod.rs
@@ -147,7 +147,13 @@ macro_rules! from_str_float_impl {
             /// representable floating-point number to the number represented
             /// by `src` (following the same rules for rounding as for the
             /// results of primitive operations).
-            #[inline]
+            // We add the `#[inline(never)]` attribute, since its content will
+            // be filled with that of `dec2flt`, which has #[inline(always)].
+            // Since `dec2flt` is generic, a normal inline attribute on this function
+            // with `dec2flt` having no attributes results in heavily repeated
+            // generation of `dec2flt`, despite the fact only a maximum of 2
+            // possible instances can ever exist. Adding #[inline(never)] avoids this.
+            #[inline(never)]
             fn from_str(src: &str) -> Result<Self, ParseFloatError> {
                 dec2flt(src)
             }
@@ -202,12 +208,14 @@ impl fmt::Display for ParseFloatError {
     }
 }
 
+#[inline]
 pub(super) fn pfe_empty() -> ParseFloatError {
     ParseFloatError { kind: FloatErrorKind::Empty }
 }
 
 // Used in unit tests, keep public.
 // This is much better than making FloatErrorKind and ParseFloatError::kind public.
+#[inline]
 pub fn pfe_invalid() -> ParseFloatError {
     ParseFloatError { kind: FloatErrorKind::Invalid }
 }
@@ -220,6 +228,7 @@ fn biased_fp_to_float<T: RawFloat>(x: BiasedFp) -> T {
 }
 
 /// Converts a decimal string into a floating point number.
+#[inline(always)] // Will be inlined into a function with `#[inline(never)]`, see above
 pub fn dec2flt<F: RawFloat>(s: &str) -> Result<F, ParseFloatError> {
     let mut s = s.as_bytes();
     let c = if let Some(&c) = s.first() {
diff --git a/library/core/src/num/dec2flt/number.rs b/library/core/src/num/dec2flt/number.rs
index 405f7e7b613..8589e2bbd4f 100644
--- a/library/core/src/num/dec2flt/number.rs
+++ b/library/core/src/num/dec2flt/number.rs
@@ -33,6 +33,7 @@ pub struct Number {
 
 impl Number {
     /// Detect if the float can be accurately reconstructed from native floats.
+    #[inline]
     fn is_fast_path<F: RawFloat>(&self) -> bool {
         F::MIN_EXPONENT_FAST_PATH <= self.exponent
             && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 86aa1e4fd20..c254803fbf6 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -392,14 +392,7 @@ impl<T> NeverShortCircuit<T> {
     pub fn wrap_mut_2<A, B>(
         mut f: impl ~const FnMut(A, B) -> T,
     ) -> impl ~const FnMut(A, B) -> Self {
-        cfg_if! {
-            if #[cfg(bootstrap)] {
-                #[allow(unused_parens)]
-                (const move |a, b| NeverShortCircuit(f(a, b)))
-            } else {
-                const move |a, b| NeverShortCircuit(f(a, b))
-            }
-        }
+        const move |a, b| NeverShortCircuit(f(a, b))
     }
 }
 
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 0f2475a8bde..cba597e66aa 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -559,6 +559,7 @@ use crate::{
 /// The `Option` type. See [the module level documentation](self) for more.
 #[derive(Copy, PartialOrd, Eq, Ord, Debug, Hash)]
 #[rustc_diagnostic_item = "Option"]
+#[cfg_attr(not(bootstrap), lang = "Option")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum Option<T> {
     /// No value.
@@ -735,48 +736,6 @@ impl<T> Option<T> {
         }
     }
 
-    /// This is a guess at how many bytes into the option the payload can be found.
-    ///
-    /// For niche-optimized types it's correct because it's pigeon-holed to only
-    /// one possible place.  For other types, it's usually correct today, but
-    /// tweaks to the layout algorithm (particularly expansions of
-    /// `-Z randomize-layout`) might make it incorrect at any point.
-    ///
-    /// It's guaranteed to be a multiple of alignment (so will always give a
-    /// correctly-aligned location) and to be within the allocated object, so
-    /// is valid to use with `offset` and to use for a zero-sized read.
-    ///
-    /// FIXME: This is a horrible hack, but allows a nice optimization.  It should
-    /// be replaced with `offset_of!` once that works on enum variants.
-    const SOME_BYTE_OFFSET_GUESS: isize = {
-        let some_uninit = Some(mem::MaybeUninit::<T>::uninit());
-        let payload_ref = some_uninit.as_ref().unwrap();
-        // SAFETY: `as_ref` gives an address inside the existing `Option`,
-        // so both pointers are derived from the same thing and the result
-        // cannot overflow an `isize`.
-        let offset = unsafe { <*const _>::byte_offset_from(payload_ref, &some_uninit) };
-
-        // The offset is into the object, so it's guaranteed to be non-negative.
-        assert!(offset >= 0);
-
-        // The payload and the overall option are aligned,
-        // so the offset will be a multiple of the alignment too.
-        assert!((offset as usize) % mem::align_of::<T>() == 0);
-
-        let max_offset = mem::size_of::<Self>() - mem::size_of::<T>();
-        if offset as usize <= max_offset {
-            // There's enough space after this offset for a `T` to exist without
-            // overflowing the bounds of the object, so let's try it.
-            offset
-        } else {
-            // The offset guess is definitely wrong, so use the address
-            // of the original option since we have it already.
-            // This also correctly handles the case of layout-optimized enums
-            // where `max_offset == 0` and thus this is the only possibility.
-            0
-        }
-    };
-
     /// Returns a slice of the contained value, if any. If this is `None`, an
     /// empty slice is returned. This can be useful to have a single type of
     /// iterator over an `Option` or slice.
@@ -809,28 +768,29 @@ impl<T> Option<T> {
     #[must_use]
     #[unstable(feature = "option_as_slice", issue = "108545")]
     pub fn as_slice(&self) -> &[T] {
-        let payload_ptr: *const T =
-            // The goal here is that both arms here are calculating exactly
-            // the same pointer, and thus it'll be folded away when the guessed
-            // offset is correct, but if the guess is wrong for some reason
-            // it'll at least still be sound, just no longer optimal.
-            if let Some(payload) = self {
-                payload
-            } else {
-                let self_ptr: *const Self = self;
-                // SAFETY: `SOME_BYTE_OFFSET_GUESS` guarantees that its value is
-                // such that this will be in-bounds of the object.
-                unsafe { self_ptr.byte_offset(Self::SOME_BYTE_OFFSET_GUESS).cast() }
-            };
-        let len = usize::from(self.is_some());
+        #[cfg(bootstrap)]
+        match self {
+            Some(value) => slice::from_ref(value),
+            None => &[],
+        }
 
+        #[cfg(not(bootstrap))]
         // SAFETY: When the `Option` is `Some`, we're using the actual pointer
         // to the payload, with a length of 1, so this is equivalent to
         // `slice::from_ref`, and thus is safe.
         // When the `Option` is `None`, the length used is 0, so to be safe it
         // just needs to be aligned, which it is because `&self` is aligned and
         // the offset used is a multiple of alignment.
-        unsafe { slice::from_raw_parts(payload_ptr, len) }
+        //
+        // In the new version, the intrinsic always returns a pointer to an
+        // in-bounds and correctly aligned position for a `T` (even if in the
+        // `None` case it's just padding).
+        unsafe {
+            slice::from_raw_parts(
+                crate::intrinsics::option_payload_ptr(crate::ptr::from_ref(self)),
+                usize::from(self.is_some()),
+            )
+        }
     }
 
     /// Returns a mutable slice of the contained value, if any. If this is
@@ -875,28 +835,32 @@ impl<T> Option<T> {
     #[must_use]
     #[unstable(feature = "option_as_slice", issue = "108545")]
     pub fn as_mut_slice(&mut self) -> &mut [T] {
-        let payload_ptr: *mut T =
-            // The goal here is that both arms here are calculating exactly
-            // the same pointer, and thus it'll be folded away when the guessed
-            // offset is correct, but if the guess is wrong for some reason
-            // it'll at least still be sound, just no longer optimal.
-            if let Some(payload) = self {
-                payload
-            } else {
-                let self_ptr: *mut Self = self;
-                // SAFETY: `SOME_BYTE_OFFSET_GUESS` guarantees that its value is
-                // such that this will be in-bounds of the object.
-                unsafe { self_ptr.byte_offset(Self::SOME_BYTE_OFFSET_GUESS).cast() }
-            };
-        let len = usize::from(self.is_some());
+        #[cfg(bootstrap)]
+        match self {
+            Some(value) => slice::from_mut(value),
+            None => &mut [],
+        }
 
+        #[cfg(not(bootstrap))]
         // SAFETY: When the `Option` is `Some`, we're using the actual pointer
         // to the payload, with a length of 1, so this is equivalent to
         // `slice::from_mut`, and thus is safe.
         // When the `Option` is `None`, the length used is 0, so to be safe it
         // just needs to be aligned, which it is because `&self` is aligned and
         // the offset used is a multiple of alignment.
-        unsafe { slice::from_raw_parts_mut(payload_ptr, len) }
+        //
+        // In the new version, the intrinsic creates a `*const T` from a
+        // mutable reference  so it is safe to cast back to a mutable pointer
+        // here. As with `as_slice`, the intrinsic always returns a pointer to
+        // an in-bounds and correctly aligned position for a `T` (even if in
+        // the `None` case it's just padding).
+        unsafe {
+            slice::from_raw_parts_mut(
+                crate::intrinsics::option_payload_ptr(crate::ptr::from_mut(self).cast_const())
+                    .cast_mut(),
+                usize::from(self.is_some()),
+            )
+        }
     }
 
     /////////////////////////////////////////////////////////////////////////
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 805a1e51ae9..dd0105c0eb4 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -111,7 +111,7 @@ pub const fn panic(expr: &'static str) -> ! {
     // truncation and padding (even though none is used here). Using
     // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
     // output binary, saving up to a few kilobytes.
-    panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
+    panic_fmt(fmt::Arguments::new_const(&[expr]));
 }
 
 /// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
@@ -120,7 +120,7 @@ pub const fn panic(expr: &'static str) -> ! {
 #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics
 #[rustc_nounwind]
 pub fn panic_nounwind(expr: &'static str) -> ! {
-    panic_nounwind_fmt(fmt::Arguments::new_v1(&[expr], &[]));
+    panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]));
 }
 
 #[inline]
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index febe57dc90b..c4b89a63019 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -1003,22 +1003,25 @@ impl<P, U> CoerceUnsized<Pin<U>> for Pin<P> where P: CoerceUnsized<U> {}
 #[stable(feature = "pin", since = "1.33.0")]
 impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
 
-/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning[^1] a `value: T` _locally_[^2].
+/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning a `value: T` locally.
 ///
-/// Unlike [`Box::pin`], this does not involve a heap allocation.
+/// Unlike [`Box::pin`], this does not create a new heap allocation. As explained
+/// below, the element might still end up on the heap however.
 ///
-/// [^1]: If the (type `T` of the) given value does not implement [`Unpin`], then this
-/// effectively pins the `value` in memory, where it will be unable to be moved.
-/// Otherwise, <code>[Pin]<[&mut] T></code> behaves like <code>[&mut] T</code>, and operations such
-/// as [`mem::replace()`][crate::mem::replace] will allow extracting that value, and therefore,
-/// moving it.
-/// See [the `Unpin` section of the `pin` module][self#unpin] for more info.
+/// The local pinning performed by this macro is usually dubbed "stack"-pinning.
+/// Outside of `async` contexts locals do indeed get stored on the stack. In
+/// `async` functions or blocks however, any locals crossing an `.await` point
+/// are part of the state captured by the `Future`, and will use the storage of
+/// those. That storage can either be on the heap or on the stack. Therefore,
+/// local pinning is a more accurate term.
 ///
-/// [^2]: This is usually dubbed "stack"-pinning. And whilst local values are almost always located
-/// in the stack (_e.g._, when within the body of a non-`async` function), the truth is that inside
-/// the body of an `async fn` or block —more generally, the body of a generator— any locals crossing
-/// an `.await` point —a `yield` point— end up being part of the state captured by the `Future` —by
-/// the `Generator`—, and thus will be stored wherever that one is.
+/// If the type of the given value does not implement [`Unpin`], then this macro
+/// pins the value in memory in a way that prevents moves. On the other hand,
+/// if the type does implement [`Unpin`], <code>[Pin]<[&mut] T></code> behaves
+/// like <code>[&mut] T</code>, and operations such as
+/// [`mem::replace()`][crate::mem::replace] or [`mem::take()`](crate::mem::take)
+/// will allow moves of the value.
+/// See [the `Unpin` section of the `pin` module][self#unpin] for details.
 ///
 /// ## Examples
 ///
@@ -1158,9 +1161,9 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
 ///
 /// If you really need to return a pinned value, consider using [`Box::pin`] instead.
 ///
-/// On the other hand, pinning to the stack[<sup>2</sup>](#fn2) using [`pin!`] is likely to be
-/// cheaper than pinning into a fresh heap allocation using [`Box::pin`]. Moreover, by virtue of not
-/// even needing an allocator, [`pin!`] is the main non-`unsafe` `#![no_std]`-compatible [`Pin`]
+/// On the other hand, local pinning using [`pin!`] is likely to be cheaper than
+/// pinning into a fresh heap allocation using [`Box::pin`]. Moreover, by virtue of not
+/// requiring an allocator, [`pin!`] is the main non-`unsafe` `#![no_std]`-compatible [`Pin`]
 /// constructor.
 ///
 /// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 6f78811a186..e12a3e378a6 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1110,7 +1110,7 @@ impl<T: Copy> Copy for (T,) {
 /// - [NaN (not a number)](#associatedconstant.NAN): this value results from
 ///   calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected
 ///   behavior:
-///   - It is unequal to any float, including itself! This is the reason `f32`
+///   - It is not equal to any float, including itself! This is the reason `f32`
 ///     doesn't implement the `Eq` trait.
 ///   - It is also neither smaller nor greater than any float, making it
 ///     impossible to sort by the default comparison operation, which is the
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index f41be46abc9..5884a8ca308 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -1135,27 +1135,58 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
 #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub const unsafe fn read<T>(src: *const T) -> T {
-    // We are calling the intrinsics directly to avoid function calls in the generated code
-    // as `intrinsics::copy_nonoverlapping` is a wrapper function.
-    extern "rust-intrinsic" {
-        #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
-        fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
-    }
+    // It would be semantically correct to implement this via `copy_nonoverlapping`
+    // and `MaybeUninit`, as was done before PR #109035. Calling `assume_init`
+    // provides enough information to know that this is a typed operation.
 
-    let mut tmp = MaybeUninit::<T>::uninit();
-    // SAFETY: the caller must guarantee that `src` is valid for reads.
-    // `src` cannot overlap `tmp` because `tmp` was just allocated on
-    // the stack as a separate allocated object.
+    // However, as of March 2023 the compiler was not capable of taking advantage
+    // of that information.  Thus the implementation here switched to an intrinsic,
+    // which lowers to `_0 = *src` in MIR, to address a few issues:
     //
-    // Also, since we just wrote a valid value into `tmp`, it is guaranteed
-    // to be properly initialized.
+    // - Using `MaybeUninit::assume_init` after a `copy_nonoverlapping` was not
+    //   turning the untyped copy into a typed load. As such, the generated
+    //   `load` in LLVM didn't get various metadata, such as `!range` (#73258),
+    //   `!nonnull`, and `!noundef`, resulting in poorer optimization.
+    // - Going through the extra local resulted in multiple extra copies, even
+    //   in optimized MIR.  (Ignoring StorageLive/Dead, the intrinsic is one
+    //   MIR statement, while the previous implementation was eight.)  LLVM
+    //   could sometimes optimize them away, but because `read` is at the core
+    //   of so many things, not having them in the first place improves what we
+    //   hand off to the backend.  For example, `mem::replace::<Big>` previously
+    //   emitted 4 `alloca` and 6 `memcpy`s, but is now 1 `alloc` and 3 `memcpy`s.
+    // - In general, this approach keeps us from getting any more bugs (like
+    //   #106369) that boil down to "`read(p)` is worse than `*p`", as this
+    //   makes them look identical to the backend (or other MIR consumers).
+    //
+    // Future enhancements to MIR optimizations might well allow this to return
+    // to the previous implementation, rather than using an intrinsic.
+
+    // SAFETY: the caller must guarantee that `src` is valid for reads.
     unsafe {
         assert_unsafe_precondition!(
             "ptr::read requires that the pointer argument is aligned and non-null",
             [T](src: *const T) => is_aligned_and_not_null(src)
         );
-        copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
-        tmp.assume_init()
+
+        #[cfg(bootstrap)]
+        {
+            // We are calling the intrinsics directly to avoid function calls in the
+            // generated code as `intrinsics::copy_nonoverlapping` is a wrapper function.
+            extern "rust-intrinsic" {
+                #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+                fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+            }
+
+            // `src` cannot overlap `tmp` because `tmp` was just allocated on
+            // the stack as a separate allocated object.
+            let mut tmp = MaybeUninit::<T>::uninit();
+            copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
+            tmp.assume_init()
+        }
+        #[cfg(not(bootstrap))]
+        {
+            crate::intrinsics::read_via_copy(src)
+        }
     }
 }
 
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index c4317799bcc..88b84bd1352 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -132,9 +132,7 @@ iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
         Self: Sized,
         F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>,
     {
-        self.as_slice().windows(2).all(|w| {
-            compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false)
-        })
+        self.as_slice().is_sorted_by(|a, b| compare(&a, &b))
     }
 }}
 
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index d319b2bc37f..57b6e0ce4bb 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -3822,7 +3822,7 @@ impl<T> [T] {
     where
         F: FnMut(&'a T, &'a T) -> Option<Ordering>,
     {
-        self.iter().is_sorted_by(|a, b| compare(*a, *b))
+        self.array_windows().all(|[a, b]| compare(a, b).map_or(false, Ordering::is_le))
     }
 
     /// Checks if the elements of this slice are sorted using the given key extraction function.
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index 95c682f42d0..772c3605562 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -13,7 +13,7 @@ use super::from_utf8_unchecked;
 use super::pattern::Pattern;
 use super::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
 use super::validations::{next_code_point, next_code_point_reverse};
-use super::LinesAnyMap;
+use super::LinesMap;
 use super::{BytesIsNotEmpty, UnsafeBytesToStr};
 use super::{CharEscapeDebugContinue, CharEscapeDefault, CharEscapeUnicode};
 use super::{IsAsciiWhitespace, IsNotEmpty, IsWhitespace};
@@ -1104,7 +1104,7 @@ generate_pattern_iterators! {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[derive(Clone, Debug)]
-pub struct Lines<'a>(pub(super) Map<SplitTerminator<'a, char>, LinesAnyMap>);
+pub struct Lines<'a>(pub(super) Map<SplitInclusive<'a, char>, LinesMap>);
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> Iterator for Lines<'a> {
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index ab2f8520ecb..2b23f64732b 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -1011,7 +1011,7 @@ impl str {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn lines(&self) -> Lines<'_> {
-        Lines(self.split_terminator('\n').map(LinesAnyMap))
+        Lines(self.split_inclusive('\n').map(LinesMap))
     }
 
     /// An iterator over the lines of a string.
@@ -2604,10 +2604,10 @@ impl Default for &mut str {
 impl_fn_for_zst! {
     /// A nameable, cloneable fn type
     #[derive(Clone)]
-    struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str {
-        let l = line.len();
-        if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] }
-        else { line }
+    struct LinesMap impl<'a> Fn = |line: &'a str| -> &'a str {
+        let Some(line) = line.strip_suffix('\n') else { return line };
+        let Some(line) = line.strip_suffix('\r') else { return line };
+        line
     };
 
     #[derive(Clone)]
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 123561873a6..2f6b1c74da0 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -1951,8 +1951,7 @@ macro_rules! if_not_8_bit {
     ($_:ident, $($tt:tt)*) => { $($tt)* };
 }
 
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic_load_store))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic_load_store = "8"))]
+#[cfg(target_has_atomic_load_store)]
 macro_rules! atomic_int {
     ($cfg_cas:meta,
      $cfg_align:meta,
@@ -3125,8 +3124,7 @@ atomic_int_ptr_sized! {
 }
 
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 fn strongest_failure_ordering(order: Ordering) -> Ordering {
     match order {
         Release => Relaxed,
@@ -3168,8 +3166,7 @@ unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_swap`.
@@ -3186,8 +3183,7 @@ unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// Returns the previous value (like __sync_fetch_and_add).
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_add`.
@@ -3204,8 +3200,7 @@ unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// Returns the previous value (like __sync_fetch_and_sub).
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_sub`.
@@ -3221,8 +3216,7 @@ unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_compare_exchange<T: Copy>(
     dst: *mut T,
@@ -3257,8 +3251,7 @@ unsafe fn atomic_compare_exchange<T: Copy>(
 }
 
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_compare_exchange_weak<T: Copy>(
     dst: *mut T,
@@ -3293,8 +3286,7 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>(
 }
 
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_and`
@@ -3310,8 +3302,7 @@ unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_nand`
@@ -3327,8 +3318,7 @@ unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_or`
@@ -3344,8 +3334,7 @@ unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_xor`
@@ -3362,8 +3351,7 @@ unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the max value (signed comparison)
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_max`
@@ -3380,8 +3368,7 @@ unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the min value (signed comparison)
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_min`
@@ -3398,8 +3385,7 @@ unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the max value (unsigned comparison)
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_umax`
@@ -3416,8 +3402,7 @@ unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the min value (unsigned comparison)
 #[inline]
-#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
-#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
+#[cfg(target_has_atomic)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_umin`
diff --git a/library/core/tests/fmt/mod.rs b/library/core/tests/fmt/mod.rs
index 61807635813..c1c80c46c78 100644
--- a/library/core/tests/fmt/mod.rs
+++ b/library/core/tests/fmt/mod.rs
@@ -22,11 +22,11 @@ fn test_pointer_formats_data_pointer() {
 #[test]
 fn test_estimated_capacity() {
     assert_eq!(format_args!("").estimated_capacity(), 0);
-    assert_eq!(format_args!("{}", "").estimated_capacity(), 0);
+    assert_eq!(format_args!("{}", {""}).estimated_capacity(), 0);
     assert_eq!(format_args!("Hello").estimated_capacity(), 5);
-    assert_eq!(format_args!("Hello, {}!", "").estimated_capacity(), 16);
-    assert_eq!(format_args!("{}, hello!", "World").estimated_capacity(), 0);
-    assert_eq!(format_args!("{}. 16-bytes piece", "World").estimated_capacity(), 32);
+    assert_eq!(format_args!("Hello, {}!", {""}).estimated_capacity(), 16);
+    assert_eq!(format_args!("{}, hello!", {"World"}).estimated_capacity(), 0);
+    assert_eq!(format_args!("{}. 16-bytes piece", {"World"}).estimated_capacity(), 32);
 }
 
 #[test]
diff --git a/library/core/tests/iter/consts.rs b/library/core/tests/iter/consts.rs
new file mode 100644
index 00000000000..d56687e48c9
--- /dev/null
+++ b/library/core/tests/iter/consts.rs
@@ -0,0 +1,36 @@
+#[test]
+fn const_manual_iter() {
+    struct S(bool);
+
+    impl const Iterator for S {
+        type Item = ();
+
+        fn next(&mut self) -> Option<Self::Item> {
+            if self.0 == false {
+                self.0 = true;
+                Some(())
+            } else {
+                None
+            }
+        }
+    }
+    const {
+        let mut val = S(false);
+        assert!(val.next().is_some());
+        assert!(val.next().is_none());
+        assert!(val.next().is_none());
+    }
+}
+
+#[test]
+fn const_range() {
+    const {
+        let mut arr = [0; 3];
+        for i in 0..arr.len() {
+            arr[i] = i;
+        }
+        assert!(arr[0] == 0);
+        assert!(arr[1] == 1);
+        assert!(arr[2] == 2);
+    }
+}
diff --git a/library/core/tests/iter/mod.rs b/library/core/tests/iter/mod.rs
index 770b6f7601f..cbb18e79e2d 100644
--- a/library/core/tests/iter/mod.rs
+++ b/library/core/tests/iter/mod.rs
@@ -20,6 +20,8 @@ mod range;
 mod sources;
 mod traits;
 
+mod consts;
+
 use core::cell::Cell;
 use core::convert::TryFrom;
 use core::iter::*;
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index ccb7be68eb1..637cc6e9f62 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -12,8 +12,11 @@
 #![feature(const_caller_location)]
 #![feature(const_cell_into_inner)]
 #![feature(const_convert)]
+#![feature(const_for)]
 #![feature(const_hash)]
 #![feature(const_heap)]
+#![feature(const_intoiterator_identity)]
+#![feature(const_iter)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_maybe_uninit_assume_init_read)]
 #![feature(const_nonnull_new)]
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 909d9bf4093..401def18458 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -2,7 +2,8 @@ use crate::io::prelude::*;
 
 use crate::env;
 use crate::fs::{self, File, OpenOptions};
-use crate::io::{ErrorKind, SeekFrom};
+use crate::io::{BorrowedBuf, ErrorKind, SeekFrom};
+use crate::mem::MaybeUninit;
 use crate::path::Path;
 use crate::str;
 use crate::sync::Arc;
@@ -402,6 +403,23 @@ fn file_test_io_seek_read_write() {
 }
 
 #[test]
+fn file_test_read_buf() {
+    let tmpdir = tmpdir();
+    let filename = &tmpdir.join("test");
+    check!(fs::write(filename, &[1, 2, 3, 4]));
+
+    let mut buf: [MaybeUninit<u8>; 128] = MaybeUninit::uninit_array();
+    let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+    let mut file = check!(File::open(filename));
+    check!(file.read_buf(buf.unfilled()));
+    assert_eq!(buf.filled(), &[1, 2, 3, 4]);
+    // File::read_buf should omit buffer initialization.
+    assert_eq!(buf.init_len(), 4);
+
+    check!(fs::remove_file(filename));
+}
+
+#[test]
 fn file_test_stat_is_correct_on_is_file() {
     let tmpdir = tmpdir();
     let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index b2b6d86134b..4b31c552eed 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -823,8 +823,22 @@ pub trait Read {
 
     /// Read the exact number of bytes required to fill `cursor`.
     ///
-    /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to
-    /// allow use with uninitialized buffers.
+    /// This is similar to the [`read_exact`](Read::read_exact) method, except
+    /// that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use
+    /// with uninitialized buffers.
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters an error of the kind [`ErrorKind::Interrupted`]
+    /// then the error is ignored and the operation will continue.
+    ///
+    /// If this function encounters an "end of file" before completely filling
+    /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
+    ///
+    /// If any other read error is encountered then this function immediately
+    /// returns.
+    ///
+    /// If this function returns an error, all bytes read will be appended to `cursor`.
     #[unstable(feature = "read_buf", issue = "78485")]
     fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> Result<()> {
         while cursor.capacity() > 0 {
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 14bfef4c7aa..0455a00956e 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -8,7 +8,7 @@ use crate::io::prelude::*;
 use crate::cell::{Cell, RefCell};
 use crate::fmt;
 use crate::fs::File;
-use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
+use crate::io::{self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
 use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantMutex, ReentrantMutexGuard};
 use crate::sys::stdio;
@@ -97,6 +97,10 @@ impl Read for StdinRaw {
         handle_ebadf(self.0.read(buf), 0)
     }
 
+    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        handle_ebadf(self.0.read_buf(buf), ())
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         handle_ebadf(self.0.read_vectored(bufs), 0)
     }
@@ -418,6 +422,9 @@ impl Read for Stdin {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.lock().read(buf)
     }
+    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.lock().read_buf(buf)
+    }
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.lock().read_vectored(bufs)
     }
@@ -450,6 +457,10 @@ impl Read for StdinLock<'_> {
         self.inner.read(buf)
     }
 
+    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.inner.read_buf(buf)
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.inner.read_vectored(bufs)
     }
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index ac09a805975..3982d363661 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -6,7 +6,7 @@ mod tests;
 use crate::io::prelude::*;
 
 use crate::fmt;
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::iter::FusedIterator;
 use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
 use crate::sys_common::net as net_imp;
@@ -619,6 +619,10 @@ impl Read for TcpStream {
         self.0.read(buf)
     }
 
+    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.0.read_buf(buf)
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.0.read_vectored(bufs)
     }
@@ -653,6 +657,10 @@ impl Read for &TcpStream {
         self.0.read(buf)
     }
 
+    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.0.read_buf(buf)
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.0.read_vectored(bufs)
     }
diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs
index e019bc0b67a..7a3c66e4504 100644
--- a/library/std/src/net/tcp/tests.rs
+++ b/library/std/src/net/tcp/tests.rs
@@ -1,6 +1,7 @@
 use crate::fmt;
 use crate::io::prelude::*;
-use crate::io::{ErrorKind, IoSlice, IoSliceMut};
+use crate::io::{BorrowedBuf, ErrorKind, IoSlice, IoSliceMut};
+use crate::mem::MaybeUninit;
 use crate::net::test::{next_test_ip4, next_test_ip6};
 use crate::net::*;
 use crate::sync::mpsc::channel;
@@ -280,6 +281,31 @@ fn partial_read() {
 }
 
 #[test]
+fn read_buf() {
+    each_ip(&mut |addr| {
+        let srv = t!(TcpListener::bind(&addr));
+        let t = thread::spawn(move || {
+            let mut s = t!(TcpStream::connect(&addr));
+            s.write_all(&[1, 2, 3, 4]).unwrap();
+        });
+
+        let mut s = t!(srv.accept()).0;
+        let mut buf: [MaybeUninit<u8>; 128] = MaybeUninit::uninit_array();
+        let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+        t!(s.read_buf(buf.unfilled()));
+        assert_eq!(buf.filled(), &[1, 2, 3, 4]);
+
+        // FIXME: sgx uses default_read_buf that initializes the buffer.
+        if cfg!(not(target_env = "sgx")) {
+            // TcpStream::read_buf should omit buffer initialization.
+            assert_eq!(buf.init_len(), 4);
+        }
+
+        t.join().ok().expect("thread panicked");
+    })
+}
+
+#[test]
 fn read_vectored() {
     each_ip(&mut |addr| {
         let srv = t!(TcpListener::bind(&addr));
diff --git a/library/std/src/os/android/net.rs b/library/std/src/os/android/net.rs
index 7cecd1bbfaa..4e88ab8ff5c 100644
--- a/library/std/src/os/android/net.rs
+++ b/library/std/src/os/android/net.rs
@@ -1,8 +1,8 @@
 //! Android-specific networking functionality.
 
-#![unstable(feature = "tcp_quickack", issue = "96256")]
+#![stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
 
-#[unstable(feature = "unix_socket_abstract", issue = "85410")]
+#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
 pub use crate::os::net::linux_ext::addr::SocketAddrExt;
 
 #[unstable(feature = "tcp_quickack", issue = "96256")]
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 258919d53a4..99a4e0b5106 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -399,7 +399,7 @@ impl<T: AsFd> AsFd for crate::sync::Arc<T> {
     }
 }
 
-#[stable(feature = "asfd_rc", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "asfd_rc", since = "1.69.0")]
 impl<T: AsFd> AsFd for crate::rc::Rc<T> {
     #[inline]
     fn as_fd(&self) -> BorrowedFd<'_> {
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index 0a4cefd2095..592e072ad90 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -254,7 +254,7 @@ impl<T: AsRawFd> AsRawFd for crate::sync::Arc<T> {
     }
 }
 
-#[stable(feature = "asfd_rc", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "asfd_rc", since = "1.69.0")]
 impl<T: AsRawFd> AsRawFd for crate::rc::Rc<T> {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
diff --git a/library/std/src/os/linux/net.rs b/library/std/src/os/linux/net.rs
index 94081c8dd31..fcb3bb83485 100644
--- a/library/std/src/os/linux/net.rs
+++ b/library/std/src/os/linux/net.rs
@@ -1,8 +1,8 @@
 //! Linux-specific networking functionality.
 
-#![unstable(feature = "tcp_quickack", issue = "96256")]
+#![stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
 
-#[unstable(feature = "unix_socket_abstract", issue = "85410")]
+#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
 pub use crate::os::net::linux_ext::addr::SocketAddrExt;
 
 #[unstable(feature = "tcp_quickack", issue = "96256")]
diff --git a/library/std/src/os/net/linux_ext/addr.rs b/library/std/src/os/net/linux_ext/addr.rs
index 85065984fbb..ea8102c9cc0 100644
--- a/library/std/src/os/net/linux_ext/addr.rs
+++ b/library/std/src/os/net/linux_ext/addr.rs
@@ -4,7 +4,7 @@ use crate::os::unix::net::SocketAddr;
 use crate::sealed::Sealed;
 
 /// Platform-specific extensions to [`SocketAddr`].
-#[unstable(feature = "unix_socket_abstract", issue = "85410")]
+#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
 pub trait SocketAddrExt: Sealed {
     /// Creates a Unix socket address in the abstract namespace.
     ///
@@ -22,7 +22,6 @@ pub trait SocketAddrExt: Sealed {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(unix_socket_abstract)]
     /// use std::os::unix::net::{UnixListener, SocketAddr};
     /// use std::os::linux::net::SocketAddrExt;
     ///
@@ -38,6 +37,7 @@ pub trait SocketAddrExt: Sealed {
     ///     Ok(())
     /// }
     /// ```
+    #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
     fn from_abstract_name<N>(name: N) -> crate::io::Result<SocketAddr>
     where
         N: AsRef<[u8]>;
@@ -47,7 +47,6 @@ pub trait SocketAddrExt: Sealed {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(unix_socket_abstract)]
     /// use std::os::unix::net::{UnixListener, SocketAddr};
     /// use std::os::linux::net::SocketAddrExt;
     ///
@@ -60,5 +59,6 @@ pub trait SocketAddrExt: Sealed {
     ///     Ok(())
     /// }
     /// ```
+    #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
     fn as_abstract_name(&self) -> Option<&[u8]>;
 }
diff --git a/library/std/src/os/net/linux_ext/mod.rs b/library/std/src/os/net/linux_ext/mod.rs
index 318ebacfd7a..e7423dce613 100644
--- a/library/std/src/os/net/linux_ext/mod.rs
+++ b/library/std/src/os/net/linux_ext/mod.rs
@@ -2,7 +2,7 @@
 
 #![doc(cfg(any(target_os = "linux", target_os = "android")))]
 
-#[unstable(feature = "unix_socket_abstract", issue = "85410")]
+#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
 pub(crate) mod addr;
 
 #[unstable(feature = "tcp_quickack", issue = "96256")]
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
index ece2b33bddf..52a0da5bf1a 100644
--- a/library/std/src/os/unix/net/addr.rs
+++ b/library/std/src/os/unix/net/addr.rs
@@ -245,12 +245,12 @@ impl SocketAddr {
     }
 }
 
-#[unstable(feature = "unix_socket_abstract", issue = "85410")]
+#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
 impl Sealed for SocketAddr {}
 
 #[doc(cfg(any(target_os = "android", target_os = "linux")))]
 #[cfg(any(doc, target_os = "android", target_os = "linux"))]
-#[unstable(feature = "unix_socket_abstract", issue = "85410")]
+#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
 impl linux_ext::addr::SocketAddrExt for SocketAddr {
     fn as_abstract_name(&self) -> Option<&[u8]> {
         if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
index 272b4f5dcd5..e64569758a0 100644
--- a/library/std/src/os/unix/net/datagram.rs
+++ b/library/std/src/os/unix/net/datagram.rs
@@ -102,7 +102,6 @@ impl UnixDatagram {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(unix_socket_abstract)]
     /// use std::os::unix::net::{UnixDatagram};
     ///
     /// fn main() -> std::io::Result<()> {
@@ -119,7 +118,7 @@ impl UnixDatagram {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+    #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
     pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixDatagram> {
         unsafe {
             let socket = UnixDatagram::unbound()?;
@@ -217,7 +216,6 @@ impl UnixDatagram {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(unix_socket_abstract)]
     /// use std::os::unix::net::{UnixDatagram};
     ///
     /// fn main() -> std::io::Result<()> {
@@ -235,7 +233,7 @@ impl UnixDatagram {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+    #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
     pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> {
         unsafe {
             cvt(libc::connect(
@@ -523,7 +521,6 @@ impl UnixDatagram {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(unix_socket_abstract)]
     /// use std::os::unix::net::{UnixDatagram};
     ///
     /// fn main() -> std::io::Result<()> {
@@ -535,7 +532,7 @@ impl UnixDatagram {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+    #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
     pub fn send_to_addr(&self, buf: &[u8], socket_addr: &SocketAddr) -> io::Result<usize> {
         unsafe {
             let count = cvt(libc::sendto(
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index 02090afc82f..83f0debe676 100644
--- a/library/std/src/os/unix/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
@@ -90,7 +90,6 @@ impl UnixListener {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(unix_socket_abstract)]
     /// use std::os::unix::net::{UnixListener};
     ///
     /// fn main() -> std::io::Result<()> {
@@ -107,7 +106,7 @@ impl UnixListener {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+    #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
     pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixListener> {
         unsafe {
             let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index dff8f6e8567..65cb4ae07a5 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -106,7 +106,6 @@ impl UnixStream {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(unix_socket_abstract)]
     /// use std::os::unix::net::{UnixListener, UnixStream};
     ///
     /// fn main() -> std::io::Result<()> {
@@ -123,7 +122,7 @@ impl UnixStream {
     ///     Ok(())
     /// }
     /// ````
-    #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+    #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
     pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result<UnixStream> {
         unsafe {
             let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 9fa8f5702a8..345d72ef867 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -308,8 +308,7 @@ pub fn get_backtrace_style() -> Option<BacktraceStyle> {
                 BacktraceStyle::Short
             }
         })
-        .unwrap_or(if cfg!(target_os = "fuchsia") {
-            // Fuchsia components default to full backtrace.
+        .unwrap_or(if crate::sys::FULL_BACKTRACE_DEFAULT {
             BacktraceStyle::Full
         } else {
             BacktraceStyle::Off
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 6f78811a186..e12a3e378a6 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -1110,7 +1110,7 @@ impl<T: Copy> Copy for (T,) {
 /// - [NaN (not a number)](#associatedconstant.NAN): this value results from
 ///   calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected
 ///   behavior:
-///   - It is unequal to any float, including itself! This is the reason `f32`
+///   - It is not equal to any float, including itself! This is the reason `f32`
 ///     doesn't implement the `Eq` trait.
 ///   - It is also neither smaller nor greater than any float, making it
 ///     impossible to sort by the default comparison operation, which is the
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 1952e19e607..80d73084c4f 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -110,7 +110,7 @@ use crate::convert::Infallible;
 use crate::ffi::OsStr;
 use crate::fmt;
 use crate::fs;
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::num::NonZeroI32;
 use crate::path::Path;
 use crate::str;
@@ -354,6 +354,10 @@ impl Read for ChildStdout {
         self.inner.read(buf)
     }
 
+    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.inner.read_buf(buf)
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.inner.read_vectored(bufs)
     }
@@ -419,6 +423,10 @@ impl Read for ChildStderr {
         self.inner.read(buf)
     }
 
+    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.inner.read_buf(buf)
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.inner.read_vectored(bufs)
     }
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index b4f6cc2daba..d7f4d335de3 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -1,7 +1,8 @@
 use crate::io::prelude::*;
 
 use super::{Command, Output, Stdio};
-use crate::io::ErrorKind;
+use crate::io::{BorrowedBuf, ErrorKind};
+use crate::mem::MaybeUninit;
 use crate::str;
 
 fn known_command() -> Command {
@@ -121,6 +122,37 @@ fn stdin_works() {
 
 #[test]
 #[cfg_attr(any(target_os = "vxworks"), ignore)]
+fn child_stdout_read_buf() {
+    let mut cmd = if cfg!(target_os = "windows") {
+        let mut cmd = Command::new("cmd");
+        cmd.arg("/C").arg("echo abc");
+        cmd
+    } else {
+        let mut cmd = shell_cmd();
+        cmd.arg("-c").arg("echo abc");
+        cmd
+    };
+    cmd.stdin(Stdio::null());
+    cmd.stdout(Stdio::piped());
+    let child = cmd.spawn().unwrap();
+
+    let mut stdout = child.stdout.unwrap();
+    let mut buf: [MaybeUninit<u8>; 128] = MaybeUninit::uninit_array();
+    let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+    stdout.read_buf(buf.unfilled()).unwrap();
+
+    // ChildStdout::read_buf should omit buffer initialization.
+    if cfg!(target_os = "windows") {
+        assert_eq!(buf.filled(), b"abc\r\n");
+        assert_eq!(buf.init_len(), 5);
+    } else {
+        assert_eq!(buf.filled(), b"abc\n");
+        assert_eq!(buf.init_len(), 4);
+    };
+}
+
+#[test]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
 fn test_process_status() {
     let mut status = if cfg!(target_os = "windows") {
         Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap()
diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs
index c6bb09b0417..492e21d9bdb 100644
--- a/library/std/src/sync/mpmc/array.rs
+++ b/library/std/src/sync/mpmc/array.rs
@@ -25,7 +25,8 @@ struct Slot<T> {
     /// The current stamp.
     stamp: AtomicUsize,
 
-    /// The message in this slot.
+    /// The message in this slot. Either read out in `read` or dropped through
+    /// `discard_all_messages`.
     msg: UnsafeCell<MaybeUninit<T>>,
 }
 
@@ -439,14 +440,13 @@ impl<T> Channel<T> {
         Some(self.cap)
     }
 
-    /// Disconnects the channel and wakes up all blocked senders and receivers.
+    /// Disconnects senders and wakes up all blocked receivers.
     ///
     /// Returns `true` if this call disconnected the channel.
-    pub(crate) fn disconnect(&self) -> bool {
+    pub(crate) fn disconnect_senders(&self) -> bool {
         let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst);
 
         if tail & self.mark_bit == 0 {
-            self.senders.disconnect();
             self.receivers.disconnect();
             true
         } else {
@@ -454,6 +454,85 @@ impl<T> Channel<T> {
         }
     }
 
+    /// Disconnects receivers and wakes up all blocked senders.
+    ///
+    /// Returns `true` if this call disconnected the channel.
+    ///
+    /// # Safety
+    /// May only be called once upon dropping the last receiver. The
+    /// destruction of all other receivers must have been observed with acquire
+    /// ordering or stronger.
+    pub(crate) unsafe fn disconnect_receivers(&self) -> bool {
+        let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst);
+        let disconnected = if tail & self.mark_bit == 0 {
+            self.senders.disconnect();
+            true
+        } else {
+            false
+        };
+
+        self.discard_all_messages(tail);
+        disconnected
+    }
+
+    /// Discards all messages.
+    ///
+    /// `tail` should be the current (and therefore last) value of `tail`.
+    ///
+    /// # Panicking
+    /// If a destructor panics, the remaining messages are leaked, matching the
+    /// behaviour of the unbounded channel.
+    ///
+    /// # Safety
+    /// This method must only be called when dropping the last receiver. The
+    /// destruction of all other receivers must have been observed with acquire
+    /// ordering or stronger.
+    unsafe fn discard_all_messages(&self, tail: usize) {
+        debug_assert!(self.is_disconnected());
+
+        // Only receivers modify `head`, so since we are the last one,
+        // this value will not change and will not be observed (since
+        // no new messages can be sent after disconnection).
+        let mut head = self.head.load(Ordering::Relaxed);
+        let tail = tail & !self.mark_bit;
+
+        let backoff = Backoff::new();
+        loop {
+            // Deconstruct the head.
+            let index = head & (self.mark_bit - 1);
+            let lap = head & !(self.one_lap - 1);
+
+            // Inspect the corresponding slot.
+            debug_assert!(index < self.buffer.len());
+            let slot = unsafe { self.buffer.get_unchecked(index) };
+            let stamp = slot.stamp.load(Ordering::Acquire);
+
+            // If the stamp is ahead of the head by 1, we may drop the message.
+            if head + 1 == stamp {
+                head = if index + 1 < self.cap {
+                    // Same lap, incremented index.
+                    // Set to `{ lap: lap, mark: 0, index: index + 1 }`.
+                    head + 1
+                } else {
+                    // One lap forward, index wraps around to zero.
+                    // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`.
+                    lap.wrapping_add(self.one_lap)
+                };
+
+                unsafe {
+                    (*slot.msg.get()).assume_init_drop();
+                }
+            // If the tail equals the head, that means the channel is empty.
+            } else if tail == head {
+                return;
+            // Otherwise, a sender is about to write into the slot, so we need
+            // to wait for it to update the stamp.
+            } else {
+                backoff.spin_heavy();
+            }
+        }
+    }
+
     /// Returns `true` if the channel is disconnected.
     pub(crate) fn is_disconnected(&self) -> bool {
         self.tail.load(Ordering::SeqCst) & self.mark_bit != 0
@@ -483,23 +562,3 @@ impl<T> Channel<T> {
         head.wrapping_add(self.one_lap) == tail & !self.mark_bit
     }
 }
-
-impl<T> Drop for Channel<T> {
-    fn drop(&mut self) {
-        // Get the index of the head.
-        let hix = self.head.load(Ordering::Relaxed) & (self.mark_bit - 1);
-
-        // Loop over all slots that hold a message and drop them.
-        for i in 0..self.len() {
-            // Compute the index of the next slot holding a message.
-            let index = if hix + i < self.cap { hix + i } else { hix + i - self.cap };
-
-            unsafe {
-                debug_assert!(index < self.buffer.len());
-                let slot = self.buffer.get_unchecked_mut(index);
-                let msg = &mut *slot.msg.get();
-                msg.as_mut_ptr().drop_in_place();
-            }
-        }
-    }
-}
diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
index 7a602cecd3b..2068dda393a 100644
--- a/library/std/src/sync/mpmc/mod.rs
+++ b/library/std/src/sync/mpmc/mod.rs
@@ -227,7 +227,7 @@ impl<T> Drop for Sender<T> {
     fn drop(&mut self) {
         unsafe {
             match &self.flavor {
-                SenderFlavor::Array(chan) => chan.release(|c| c.disconnect()),
+                SenderFlavor::Array(chan) => chan.release(|c| c.disconnect_senders()),
                 SenderFlavor::List(chan) => chan.release(|c| c.disconnect_senders()),
                 SenderFlavor::Zero(chan) => chan.release(|c| c.disconnect()),
             }
@@ -403,7 +403,7 @@ impl<T> Drop for Receiver<T> {
     fn drop(&mut self) {
         unsafe {
             match &self.flavor {
-                ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect()),
+                ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect_receivers()),
                 ReceiverFlavor::List(chan) => chan.release(|c| c.disconnect_receivers()),
                 ReceiverFlavor::Zero(chan) => chan.release(|c| c.disconnect()),
             }
diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs
index 9d2f92ffc9b..632709fd98d 100644
--- a/library/std/src/sync/mpsc/sync_tests.rs
+++ b/library/std/src/sync/mpsc/sync_tests.rs
@@ -1,5 +1,6 @@
 use super::*;
 use crate::env;
+use crate::rc::Rc;
 use crate::sync::mpmc::SendTimeoutError;
 use crate::thread;
 use crate::time::Duration;
@@ -656,3 +657,15 @@ fn issue_15761() {
         repro()
     }
 }
+
+#[test]
+fn drop_unreceived() {
+    let (tx, rx) = sync_channel::<Rc<()>>(1);
+    let msg = Rc::new(());
+    let weak = Rc::downgrade(&msg);
+    assert!(tx.send(msg).is_ok());
+    drop(rx);
+    // Messages should be dropped immediately when the last receiver is destroyed.
+    assert!(weak.upgrade().is_none());
+    drop(tx);
+}
diff --git a/library/std/src/sync/remutex.rs b/library/std/src/sync/remutex.rs
index 4c054da6471..519ec2c32bd 100644
--- a/library/std/src/sync/remutex.rs
+++ b/library/std/src/sync/remutex.rs
@@ -35,7 +35,7 @@ use crate::sys::locks as sys;
 /// `owner` can be checked by other threads that want to see if they already
 /// hold the lock, so needs to be atomic. If it compares equal, we're on the
 /// same thread that holds the mutex and memory access can use relaxed ordering
-/// since we're not dealing with multiple threads. If it compares unequal,
+/// since we're not dealing with multiple threads. If it's not equal,
 /// synchronization is left to the mutex, making relaxed memory ordering for
 /// the `owner` field fine in all cases.
 pub struct ReentrantMutex<T> {
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index c080c176a2a..e767b2866cb 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -76,3 +76,12 @@ cfg_if::cfg_if! {
         pub mod c;
     }
 }
+
+cfg_if::cfg_if! {
+    // Fuchsia components default to full backtrace.
+    if #[cfg(target_os = "fuchsia")] {
+        pub const FULL_BACKTRACE_DEFAULT: bool = true;
+    } else {
+        pub const FULL_BACKTRACE_DEFAULT: bool = false;
+    }
+}
diff --git a/library/std/src/sys/sgx/fd.rs b/library/std/src/sys/sgx/fd.rs
index e5dc5b5adaa..0c02a107691 100644
--- a/library/std/src/sys/sgx/fd.rs
+++ b/library/std/src/sys/sgx/fd.rs
@@ -1,7 +1,7 @@
 use fortanix_sgx_abi::Fd;
 
 use super::abi::usercalls;
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::mem;
 use crate::sys::{AsInner, FromInner, IntoInner};
 
@@ -30,6 +30,10 @@ impl FileDesc {
         usercalls::read(self.fd, &mut [IoSliceMut::new(buf)])
     }
 
+    pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        crate::io::default_read_buf(|b| self.read(b), buf)
+    }
+
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         usercalls::read(self.fd, bufs)
     }
diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs
index 4c4cd7d1d1d..923be5eb944 100644
--- a/library/std/src/sys/sgx/net.rs
+++ b/library/std/src/sys/sgx/net.rs
@@ -1,6 +1,6 @@
 use crate::error;
 use crate::fmt;
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
 use crate::sync::Arc;
 use crate::sys::fd::FileDesc;
@@ -144,6 +144,10 @@ impl TcpStream {
         self.inner.inner.read(buf)
     }
 
+    pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.inner.inner.read_buf(buf)
+    }
+
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.inner.inner.read_vectored(bufs)
     }
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 9874af4d3e2..ce5c048f252 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -469,6 +469,15 @@ impl<'a> Read for &'a FileDesc {
     fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
         (**self).read_buf(cursor)
     }
+
+    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        (**self).read_vectored(bufs)
+    }
+
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        (**self).is_read_vectored()
+    }
 }
 
 impl AsInner<OwnedFd> for FileDesc {
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index 8e05b618daa..f84240d268f 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -1,6 +1,6 @@
 use crate::cmp;
 use crate::ffi::CStr;
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::mem;
 use crate::net::{Shutdown, SocketAddr};
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
@@ -242,19 +242,35 @@ impl Socket {
         self.0.duplicate().map(Socket)
     }
 
-    fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
+    fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> {
         let ret = cvt(unsafe {
-            libc::recv(self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags)
+            libc::recv(
+                self.as_raw_fd(),
+                buf.as_mut().as_mut_ptr() as *mut c_void,
+                buf.capacity(),
+                flags,
+            )
         })?;
-        Ok(ret as usize)
+        unsafe {
+            buf.advance(ret as usize);
+        }
+        Ok(())
     }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
-        self.recv_with_flags(buf, 0)
+        let mut buf = BorrowedBuf::from(buf);
+        self.recv_with_flags(buf.unfilled(), 0)?;
+        Ok(buf.len())
     }
 
     pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
-        self.recv_with_flags(buf, MSG_PEEK)
+        let mut buf = BorrowedBuf::from(buf);
+        self.recv_with_flags(buf.unfilled(), MSG_PEEK)?;
+        Ok(buf.len())
+    }
+
+    pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.recv_with_flags(buf, 0)
     }
 
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs
index a744d0ab640..dc17c9fac46 100644
--- a/library/std/src/sys/unix/pipe.rs
+++ b/library/std/src/sys/unix/pipe.rs
@@ -1,4 +1,4 @@
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::mem;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::sys::fd::FileDesc;
@@ -49,6 +49,10 @@ impl AnonPipe {
         self.0.read(buf)
     }
 
+    pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.0.read_buf(buf)
+    }
+
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.0.read_vectored(bufs)
     }
diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs
index b3626c564e8..a26f20795a1 100644
--- a/library/std/src/sys/unix/stdio.rs
+++ b/library/std/src/sys/unix/stdio.rs
@@ -1,4 +1,4 @@
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::mem::ManuallyDrop;
 use crate::os::unix::io::FromRawFd;
 use crate::sys::fd::FileDesc;
@@ -18,6 +18,10 @@ impl io::Read for Stdin {
         unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read(buf) }
     }
 
+    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_buf(buf) }
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_vectored(bufs) }
     }
diff --git a/library/std/src/sys/unsupported/net.rs b/library/std/src/sys/unsupported/net.rs
index a5204a08453..bbc52703f96 100644
--- a/library/std/src/sys/unsupported/net.rs
+++ b/library/std/src/sys/unsupported/net.rs
@@ -1,5 +1,5 @@
 use crate::fmt;
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
 use crate::sys::unsupported;
 use crate::time::Duration;
@@ -39,6 +39,10 @@ impl TcpStream {
         self.0
     }
 
+    pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.0
+    }
+
     pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.0
     }
diff --git a/library/std/src/sys/unsupported/pipe.rs b/library/std/src/sys/unsupported/pipe.rs
index 0bba673b458..d7d8f297ae5 100644
--- a/library/std/src/sys/unsupported/pipe.rs
+++ b/library/std/src/sys/unsupported/pipe.rs
@@ -1,4 +1,4 @@
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 
 pub struct AnonPipe(!);
 
@@ -7,6 +7,10 @@ impl AnonPipe {
         self.0
     }
 
+    pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.0
+    }
+
     pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.0
     }
diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs
index 0b9c8e61db8..191db4b60f7 100644
--- a/library/std/src/sys/wasi/fd.rs
+++ b/library/std/src/sys/wasi/fd.rs
@@ -2,7 +2,7 @@
 #![allow(dead_code)]
 
 use super::err2io;
-use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
 use crate::mem;
 use crate::net::Shutdown;
 use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
@@ -46,6 +46,22 @@ impl WasiFd {
         unsafe { wasi::fd_read(self.as_raw_fd() as wasi::Fd, iovec(bufs)).map_err(err2io) }
     }
 
+    pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
+        unsafe {
+            let bufs = [wasi::Iovec {
+                buf: buf.as_mut().as_mut_ptr() as *mut u8,
+                buf_len: buf.capacity(),
+            }];
+            match wasi::fd_read(self.as_raw_fd() as wasi::Fd, &bufs) {
+                Ok(n) => {
+                    buf.advance(n);
+                    Ok(())
+                }
+                Err(e) => Err(err2io(e)),
+            }
+        }
+    }
+
     pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
         unsafe { wasi::fd_write(self.as_raw_fd() as wasi::Fd, ciovec(bufs)).map_err(err2io) }
     }
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index d4866bbc32b..3a205267e34 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -441,7 +441,7 @@ impl File {
     }
 
     pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
-        crate::io::default_read_buf(|buf| self.read(buf), cursor)
+        self.fd.read_buf(cursor)
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs
index cf4ebba1a39..59d94a3686d 100644
--- a/library/std/src/sys/wasi/net.rs
+++ b/library/std/src/sys/wasi/net.rs
@@ -3,7 +3,7 @@
 use super::err2io;
 use super::fd::WasiFd;
 use crate::fmt;
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
 use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::sys::unsupported;
@@ -91,6 +91,10 @@ impl TcpStream {
         self.read_vectored(&mut [IoSliceMut::new(buf)])
     }
 
+    pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.socket().as_inner().read_buf(buf)
+    }
+
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.socket().as_inner().read(bufs)
     }
diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs
index 30356fa8519..43c0cdb657e 100644
--- a/library/std/src/sys/windows/args.rs
+++ b/library/std/src/sys/windows/args.rs
@@ -11,10 +11,11 @@ use crate::fmt;
 use crate::io;
 use crate::num::NonZeroU16;
 use crate::os::windows::prelude::*;
-use crate::path::PathBuf;
-use crate::sys::c;
+use crate::path::{Path, PathBuf};
+use crate::sys::path::get_long_path;
 use crate::sys::process::ensure_no_nuls;
 use crate::sys::windows::os::current_exe;
+use crate::sys::{c, to_u16s};
 use crate::sys_common::wstr::WStrUnits;
 use crate::vec;
 
@@ -311,7 +312,7 @@ pub(crate) fn make_bat_command_line(
 /// Takes a path and tries to return a non-verbatim path.
 ///
 /// This is necessary because cmd.exe does not support verbatim paths.
-pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
+pub(crate) fn to_user_path(path: &Path) -> io::Result<Vec<u16>> {
     use crate::ptr;
     use crate::sys::windows::fill_utf16_buf;
 
@@ -324,6 +325,8 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
     const N: u16 = b'N' as _;
     const C: u16 = b'C' as _;
 
+    let mut path = to_u16s(path)?;
+
     // Early return if the path is too long to remove the verbatim prefix.
     const LEGACY_MAX_PATH: usize = 260;
     if path.len() > LEGACY_MAX_PATH {
@@ -337,7 +340,13 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
             fill_utf16_buf(
                 |buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()),
                 |full_path: &[u16]| {
-                    if full_path == &path[4..path.len() - 1] { full_path.into() } else { path }
+                    if full_path == &path[4..path.len() - 1] {
+                        let mut path: Vec<u16> = full_path.into();
+                        path.push(0);
+                        path
+                    } else {
+                        path
+                    }
                 },
             )
         },
@@ -350,7 +359,9 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
                 |buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()),
                 |full_path: &[u16]| {
                     if full_path == &path[6..path.len() - 1] {
-                        full_path.into()
+                        let mut path: Vec<u16> = full_path.into();
+                        path.push(0);
+                        path
                     } else {
                         // Restore the 'C' in "UNC".
                         path[6] = b'C' as u16;
@@ -360,6 +371,6 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
             )
         },
         // For everything else, leave the path unchanged.
-        _ => Ok(path),
+        _ => get_long_path(path, false),
     }
 }
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 5d150eca00e..1f4092ad738 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -296,7 +296,6 @@ pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _;
 
 pub const STATUS_PENDING: NTSTATUS = 0x103 as _;
 pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _;
-pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _;
 
 // Equivalent to the `NT_SUCCESS` C preprocessor macro.
 // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
@@ -1282,6 +1281,46 @@ extern "system" {
     ) -> NTSTATUS;
 }
 
+#[link(name = "ntdll")]
+extern "system" {
+    pub fn NtCreateFile(
+        FileHandle: *mut HANDLE,
+        DesiredAccess: ACCESS_MASK,
+        ObjectAttributes: *const OBJECT_ATTRIBUTES,
+        IoStatusBlock: *mut IO_STATUS_BLOCK,
+        AllocationSize: *mut i64,
+        FileAttributes: ULONG,
+        ShareAccess: ULONG,
+        CreateDisposition: ULONG,
+        CreateOptions: ULONG,
+        EaBuffer: *mut c_void,
+        EaLength: ULONG,
+    ) -> NTSTATUS;
+    pub fn NtReadFile(
+        FileHandle: BorrowedHandle<'_>,
+        Event: HANDLE,
+        ApcRoutine: Option<IO_APC_ROUTINE>,
+        ApcContext: *mut c_void,
+        IoStatusBlock: &mut IO_STATUS_BLOCK,
+        Buffer: *mut crate::mem::MaybeUninit<u8>,
+        Length: ULONG,
+        ByteOffset: Option<&LARGE_INTEGER>,
+        Key: Option<&ULONG>,
+    ) -> NTSTATUS;
+    pub fn NtWriteFile(
+        FileHandle: BorrowedHandle<'_>,
+        Event: HANDLE,
+        ApcRoutine: Option<IO_APC_ROUTINE>,
+        ApcContext: *mut c_void,
+        IoStatusBlock: &mut IO_STATUS_BLOCK,
+        Buffer: *const u8,
+        Length: ULONG,
+        ByteOffset: Option<&LARGE_INTEGER>,
+        Key: Option<&ULONG>,
+    ) -> NTSTATUS;
+    pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> ULONG;
+}
+
 // Functions that aren't available on every version of Windows that we support,
 // but we still use them and just provide some form of a fallback implementation.
 compat_fn_with_fallback! {
@@ -1322,52 +1361,6 @@ compat_fn_optional! {
 compat_fn_with_fallback! {
     pub static NTDLL: &CStr = ansi_str!("ntdll");
 
-    pub fn NtCreateFile(
-        FileHandle: *mut HANDLE,
-        DesiredAccess: ACCESS_MASK,
-        ObjectAttributes: *const OBJECT_ATTRIBUTES,
-        IoStatusBlock: *mut IO_STATUS_BLOCK,
-        AllocationSize: *mut i64,
-        FileAttributes: ULONG,
-        ShareAccess: ULONG,
-        CreateDisposition: ULONG,
-        CreateOptions: ULONG,
-        EaBuffer: *mut c_void,
-        EaLength: ULONG
-    ) -> NTSTATUS {
-        STATUS_NOT_IMPLEMENTED
-    }
-    pub fn NtReadFile(
-        FileHandle: BorrowedHandle<'_>,
-        Event: HANDLE,
-        ApcRoutine: Option<IO_APC_ROUTINE>,
-        ApcContext: *mut c_void,
-        IoStatusBlock: &mut IO_STATUS_BLOCK,
-        Buffer: *mut crate::mem::MaybeUninit<u8>,
-        Length: ULONG,
-        ByteOffset: Option<&LARGE_INTEGER>,
-        Key: Option<&ULONG>
-    ) -> NTSTATUS {
-        STATUS_NOT_IMPLEMENTED
-    }
-    pub fn NtWriteFile(
-        FileHandle: BorrowedHandle<'_>,
-        Event: HANDLE,
-        ApcRoutine: Option<IO_APC_ROUTINE>,
-        ApcContext: *mut c_void,
-        IoStatusBlock: &mut IO_STATUS_BLOCK,
-        Buffer: *const u8,
-        Length: ULONG,
-        ByteOffset: Option<&LARGE_INTEGER>,
-        Key: Option<&ULONG>
-    ) -> NTSTATUS {
-        STATUS_NOT_IMPLEMENTED
-    }
-    pub fn RtlNtStatusToDosError(
-        Status: NTSTATUS
-    ) -> ULONG {
-        Status as ULONG
-    }
     pub fn NtCreateKeyedEvent(
         KeyedEventHandle: LPHANDLE,
         DesiredAccess: ACCESS_MASK,
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index d2c597664fa..373157bd9e8 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -1236,7 +1236,17 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
 }
 
 pub fn stat(path: &Path) -> io::Result<FileAttr> {
-    metadata(path, ReparsePoint::Follow)
+    match metadata(path, ReparsePoint::Follow) {
+        Err(err) if err.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => {
+            if let Ok(attrs) = lstat(path) {
+                if !attrs.file_type().is_symlink() {
+                    return Ok(attrs);
+                }
+            }
+            Err(err)
+        }
+        result => result,
+    }
 }
 
 pub fn lstat(path: &Path) -> io::Result<FileAttr> {
diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs
index ae33d48c612..b290f4070e8 100644
--- a/library/std/src/sys/windows/handle.rs
+++ b/library/std/src/sys/windows/handle.rs
@@ -327,7 +327,16 @@ impl<'a> Read for &'a Handle {
         (**self).read(buf)
     }
 
+    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        (**self).read_buf(buf)
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         (**self).read_vectored(bufs)
     }
+
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        (**self).is_read_vectored()
+    }
 }
diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs
index e0701a498fa..ee1f5482b47 100644
--- a/library/std/src/sys/windows/net.rs
+++ b/library/std/src/sys/windows/net.rs
@@ -1,7 +1,7 @@
 #![unstable(issue = "none", feature = "windows_net")]
 
 use crate::cmp;
-use crate::io::{self, IoSlice, IoSliceMut, Read};
+use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut, Read};
 use crate::mem;
 use crate::net::{Shutdown, SocketAddr};
 use crate::os::windows::io::{
@@ -214,28 +214,38 @@ impl Socket {
         Ok(Self(self.0.try_clone()?))
     }
 
-    fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
+    fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> {
         // On unix when a socket is shut down all further reads return 0, so we
         // do the same on windows to map a shut down socket to returning EOF.
-        let length = cmp::min(buf.len(), i32::MAX as usize) as i32;
-        let result =
-            unsafe { c::recv(self.as_raw_socket(), buf.as_mut_ptr() as *mut _, length, flags) };
+        let length = cmp::min(buf.capacity(), i32::MAX as usize) as i32;
+        let result = unsafe {
+            c::recv(self.as_raw_socket(), buf.as_mut().as_mut_ptr() as *mut _, length, flags)
+        };
 
         match result {
             c::SOCKET_ERROR => {
                 let error = unsafe { c::WSAGetLastError() };
 
                 if error == c::WSAESHUTDOWN {
-                    Ok(0)
+                    Ok(())
                 } else {
                     Err(io::Error::from_raw_os_error(error))
                 }
             }
-            _ => Ok(result as usize),
+            _ => {
+                unsafe { buf.advance(result as usize) };
+                Ok(())
+            }
         }
     }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut buf = BorrowedBuf::from(buf);
+        self.recv_with_flags(buf.unfilled(), 0)?;
+        Ok(buf.len())
+    }
+
+    pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
         self.recv_with_flags(buf, 0)
     }
 
@@ -277,7 +287,9 @@ impl Socket {
     }
 
     pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
-        self.recv_with_flags(buf, c::MSG_PEEK)
+        let mut buf = BorrowedBuf::from(buf);
+        self.recv_with_flags(buf.unfilled(), c::MSG_PEEK)?;
+        Ok(buf.len())
     }
 
     fn recv_from_with_flags(
diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs
index beeca1917a9..c3573d14c7f 100644
--- a/library/std/src/sys/windows/path.rs
+++ b/library/std/src/sys/windows/path.rs
@@ -220,6 +220,19 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
 ///
 /// This path may or may not have a verbatim prefix.
 pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
+    let path = to_u16s(path)?;
+    get_long_path(path, true)
+}
+
+/// Get a normalized absolute path that can bypass path length limits.
+///
+/// Setting prefer_verbatim to true suggests a stronger preference for verbatim
+/// paths even when not strictly necessary. This allows the Windows API to avoid
+/// repeating our work. However, if the path may be given back to users or
+/// passed to other application then it's preferable to use non-verbatim paths
+/// when possible. Non-verbatim paths are better understood by users and handled
+/// by more software.
+pub(crate) fn get_long_path(mut path: Vec<u16>, prefer_verbatim: bool) -> io::Result<Vec<u16>> {
     // Normally the MAX_PATH is 260 UTF-16 code units (including the NULL).
     // However, for APIs such as CreateDirectory[1], the limit is 248.
     //
@@ -243,7 +256,6 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
     // \\?\UNC\
     const UNC_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP, U, N, C, SEP];
 
-    let mut path = to_u16s(path)?;
     if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) || path == &[0] {
         // Early return for paths that are already verbatim or empty.
         return Ok(path);
@@ -275,29 +287,34 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
         |mut absolute| {
             path.clear();
 
-            // Secondly, add the verbatim prefix. This is easier here because we know the
-            // path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
-            let prefix = match absolute {
-                // C:\ => \\?\C:\
-                [_, COLON, SEP, ..] => VERBATIM_PREFIX,
-                // \\.\ => \\?\
-                [SEP, SEP, DOT, SEP, ..] => {
-                    absolute = &absolute[4..];
-                    VERBATIM_PREFIX
-                }
-                // Leave \\?\ and \??\ as-is.
-                [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[],
-                // \\ => \\?\UNC\
-                [SEP, SEP, ..] => {
-                    absolute = &absolute[2..];
-                    UNC_PREFIX
-                }
-                // Anything else we leave alone.
-                _ => &[],
-            };
-
-            path.reserve_exact(prefix.len() + absolute.len() + 1);
-            path.extend_from_slice(prefix);
+            // Only prepend the prefix if needed.
+            if prefer_verbatim || absolute.len() + 1 >= LEGACY_MAX_PATH {
+                // Secondly, add the verbatim prefix. This is easier here because we know the
+                // path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
+                let prefix = match absolute {
+                    // C:\ => \\?\C:\
+                    [_, COLON, SEP, ..] => VERBATIM_PREFIX,
+                    // \\.\ => \\?\
+                    [SEP, SEP, DOT, SEP, ..] => {
+                        absolute = &absolute[4..];
+                        VERBATIM_PREFIX
+                    }
+                    // Leave \\?\ and \??\ as-is.
+                    [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[],
+                    // \\ => \\?\UNC\
+                    [SEP, SEP, ..] => {
+                        absolute = &absolute[2..];
+                        UNC_PREFIX
+                    }
+                    // Anything else we leave alone.
+                    _ => &[],
+                };
+
+                path.reserve_exact(prefix.len() + absolute.len() + 1);
+                path.extend_from_slice(prefix);
+            } else {
+                path.reserve_exact(absolute.len() + 1);
+            }
             path.extend_from_slice(absolute);
             path.push(0);
         },
diff --git a/library/std/src/sys/windows/pipe.rs b/library/std/src/sys/windows/pipe.rs
index 7b25edaa556..0780b29584d 100644
--- a/library/std/src/sys/windows/pipe.rs
+++ b/library/std/src/sys/windows/pipe.rs
@@ -1,7 +1,7 @@
 use crate::os::windows::prelude::*;
 
 use crate::ffi::OsStr;
-use crate::io::{self, IoSlice, IoSliceMut, Read};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
 use crate::mem;
 use crate::path::Path;
 use crate::ptr;
@@ -252,6 +252,28 @@ impl AnonPipe {
         }
     }
 
+    pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
+        let result = unsafe {
+            let len = crate::cmp::min(buf.capacity(), c::DWORD::MAX as usize) as c::DWORD;
+            self.alertable_io_internal(c::ReadFileEx, buf.as_mut().as_mut_ptr() as _, len)
+        };
+
+        match result {
+            // The special treatment of BrokenPipe is to deal with Windows
+            // pipe semantics, which yields this error when *reading* from
+            // a pipe after the other end has closed; we interpret that as
+            // EOF on the pipe.
+            Err(ref e) if e.kind() == io::ErrorKind::BrokenPipe => Ok(()),
+            Err(e) => Err(e),
+            Ok(n) => {
+                unsafe {
+                    buf.advance(n);
+                }
+                Ok(())
+            }
+        }
+    }
+
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.inner.read_vectored(bufs)
     }
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 10bc949e1f4..1c73b64e250 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -266,11 +266,7 @@ impl Command {
         let (program, mut cmd_str) = if is_batch_file {
             (
                 command_prompt()?,
-                args::make_bat_command_line(
-                    &args::to_user_path(program)?,
-                    &self.args,
-                    self.force_quotes_enabled,
-                )?,
+                args::make_bat_command_line(&program, &self.args, self.force_quotes_enabled)?,
             )
         } else {
             let cmd_str = make_command_line(&self.program, &self.args, self.force_quotes_enabled)?;
@@ -410,7 +406,7 @@ fn resolve_exe<'a>(
         if has_exe_suffix {
             // The application name is a path to a `.exe` file.
             // Let `CreateProcessW` figure out if it exists or not.
-            return path::maybe_verbatim(Path::new(exe_path));
+            return args::to_user_path(Path::new(exe_path));
         }
         let mut path = PathBuf::from(exe_path);
 
@@ -422,7 +418,7 @@ fn resolve_exe<'a>(
             // It's ok to use `set_extension` here because the intent is to
             // remove the extension that was just added.
             path.set_extension("");
-            return path::maybe_verbatim(&path);
+            return args::to_user_path(&path);
         }
     } else {
         ensure_no_nuls(exe_path)?;
@@ -510,7 +506,7 @@ where
 /// Check if a file exists without following symlinks.
 fn program_exists(path: &Path) -> Option<Vec<u16>> {
     unsafe {
-        let path = path::maybe_verbatim(path).ok()?;
+        let path = args::to_user_path(path).ok()?;
         // Getting attributes using `GetFileAttributesW` does not follow symlinks
         // and it will almost always be successful if the link exists.
         // There are some exceptions for special system files (e.g. the pagefile)
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index 85ecc1def3a..eb427dbda23 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -4,7 +4,7 @@ mod tests;
 use crate::cmp;
 use crate::convert::{TryFrom, TryInto};
 use crate::fmt;
-use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut};
 use crate::mem;
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
 use crate::ptr;
@@ -272,6 +272,10 @@ impl TcpStream {
         self.inner.read(buf)
     }
 
+    pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.inner.read_buf(buf)
+    }
+
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.inner.read_vectored(bufs)
     }
diff --git a/library/test/src/console.rs b/library/test/src/console.rs
index 1ee68c8540b..7eee4ca2361 100644
--- a/library/test/src/console.rs
+++ b/library/test/src/console.rs
@@ -41,6 +41,46 @@ impl<T: Write> Write for OutputLocation<T> {
     }
 }
 
+pub struct ConsoleTestDiscoveryState {
+    pub log_out: Option<File>,
+    pub tests: usize,
+    pub benchmarks: usize,
+    pub ignored: usize,
+    pub options: Options,
+}
+
+impl ConsoleTestDiscoveryState {
+    pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestDiscoveryState> {
+        let log_out = match opts.logfile {
+            Some(ref path) => Some(File::create(path)?),
+            None => None,
+        };
+
+        Ok(ConsoleTestDiscoveryState {
+            log_out,
+            tests: 0,
+            benchmarks: 0,
+            ignored: 0,
+            options: opts.options,
+        })
+    }
+
+    pub fn write_log<F, S>(&mut self, msg: F) -> io::Result<()>
+    where
+        S: AsRef<str>,
+        F: FnOnce() -> S,
+    {
+        match self.log_out {
+            None => Ok(()),
+            Some(ref mut o) => {
+                let msg = msg();
+                let msg = msg.as_ref();
+                o.write_all(msg.as_bytes())
+            }
+        }
+    }
+}
+
 pub struct ConsoleTestState {
     pub log_out: Option<File>,
     pub total: usize,
@@ -138,53 +178,44 @@ impl ConsoleTestState {
 
 // List the tests to console, and optionally to logfile. Filters are honored.
 pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
-    let mut output = match term::stdout() {
+    let output = match term::stdout() {
         None => OutputLocation::Raw(io::stdout().lock()),
         Some(t) => OutputLocation::Pretty(t),
     };
 
-    let quiet = opts.format == OutputFormat::Terse;
-    let mut st = ConsoleTestState::new(opts)?;
-
-    let mut ntest = 0;
-    let mut nbench = 0;
+    let mut out: Box<dyn OutputFormatter> = match opts.format {
+        OutputFormat::Pretty | OutputFormat::Junit => {
+            Box::new(PrettyFormatter::new(output, false, 0, false, None))
+        }
+        OutputFormat::Terse => Box::new(TerseFormatter::new(output, false, 0, false)),
+        OutputFormat::Json => Box::new(JsonFormatter::new(output)),
+    };
+    let mut st = ConsoleTestDiscoveryState::new(opts)?;
 
+    out.write_discovery_start()?;
     for test in filter_tests(opts, tests).into_iter() {
         use crate::TestFn::*;
 
-        let TestDescAndFn { desc: TestDesc { name, .. }, testfn } = test;
+        let TestDescAndFn { desc, testfn } = test;
 
         let fntype = match testfn {
             StaticTestFn(..) | DynTestFn(..) => {
-                ntest += 1;
+                st.tests += 1;
                 "test"
             }
             StaticBenchFn(..) | DynBenchFn(..) => {
-                nbench += 1;
+                st.benchmarks += 1;
                 "benchmark"
             }
         };
 
-        writeln!(output, "{name}: {fntype}")?;
-        st.write_log(|| format!("{fntype} {name}\n"))?;
-    }
+        st.ignored += if desc.ignore { 1 } else { 0 };
 
-    fn plural(count: u32, s: &str) -> String {
-        match count {
-            1 => format!("1 {s}"),
-            n => format!("{n} {s}s"),
-        }
+        out.write_test_discovered(&desc, fntype)?;
+        st.write_log(|| format!("{fntype} {}\n", desc.name))?;
     }
 
-    if !quiet {
-        if ntest != 0 || nbench != 0 {
-            writeln!(output)?;
-        }
-
-        writeln!(output, "{}, {}", plural(ntest, "test"), plural(nbench, "benchmark"))?;
-    }
-
-    Ok(())
+    out.write_discovery_finish(&st)
 }
 
 // Updates `ConsoleTestState` depending on result of the test execution.
diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs
index 95d2faf2506..40976ec5e1c 100644
--- a/library/test/src/formatters/json.rs
+++ b/library/test/src/formatters/json.rs
@@ -2,7 +2,7 @@ use std::{borrow::Cow, io, io::prelude::Write};
 
 use super::OutputFormatter;
 use crate::{
-    console::{ConsoleTestState, OutputLocation},
+    console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation},
     test_result::TestResult,
     time,
     types::TestDesc,
@@ -60,6 +60,56 @@ impl<T: Write> JsonFormatter<T> {
 }
 
 impl<T: Write> OutputFormatter for JsonFormatter<T> {
+    fn write_discovery_start(&mut self) -> io::Result<()> {
+        self.writeln_message(&format!(r#"{{ "type": "suite", "event": "discovery" }}"#))
+    }
+
+    fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> {
+        let TestDesc {
+            name,
+            ignore,
+            ignore_message,
+            #[cfg(not(bootstrap))]
+            source_file,
+            #[cfg(not(bootstrap))]
+            start_line,
+            #[cfg(not(bootstrap))]
+            start_col,
+            #[cfg(not(bootstrap))]
+            end_line,
+            #[cfg(not(bootstrap))]
+            end_col,
+            ..
+        } = desc;
+
+        #[cfg(bootstrap)]
+        let source_file = "";
+        #[cfg(bootstrap)]
+        let start_line = 0;
+        #[cfg(bootstrap)]
+        let start_col = 0;
+        #[cfg(bootstrap)]
+        let end_line = 0;
+        #[cfg(bootstrap)]
+        let end_col = 0;
+
+        self.writeln_message(&format!(
+            r#"{{ "type": "{test_type}", "event": "discovered", "name": "{}", "ignore": {ignore}, "ignore_message": "{}", "source_path": "{}", "start_line": {start_line}, "start_col": {start_col}, "end_line": {end_line}, "end_col": {end_col} }}"#,
+            EscapedString(name.as_slice()),
+            ignore_message.unwrap_or(""),
+            EscapedString(source_file),
+        ))
+    }
+
+    fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()> {
+        let ConsoleTestDiscoveryState { tests, benchmarks, ignored, .. } = state;
+
+        let total = tests + benchmarks;
+        self.writeln_message(&format!(
+            r#"{{ "type": "suite", "event": "completed", "tests": {tests}, "benchmarks": {benchmarks}, "total": {total}, "ignored": {ignored} }}"#
+        ))
+    }
+
     fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> {
         let shuffle_seed_json = if let Some(shuffle_seed) = shuffle_seed {
             format!(r#", "shuffle_seed": {shuffle_seed}"#)
diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs
index 7a40ce33cb7..2e07ce3c099 100644
--- a/library/test/src/formatters/junit.rs
+++ b/library/test/src/formatters/junit.rs
@@ -3,7 +3,7 @@ use std::time::Duration;
 
 use super::OutputFormatter;
 use crate::{
-    console::{ConsoleTestState, OutputLocation},
+    console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation},
     test_result::TestResult,
     time,
     types::{TestDesc, TestType},
@@ -27,6 +27,18 @@ impl<T: Write> JunitFormatter<T> {
 }
 
 impl<T: Write> OutputFormatter for JunitFormatter<T> {
+    fn write_discovery_start(&mut self) -> io::Result<()> {
+        Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!"))
+    }
+
+    fn write_test_discovered(&mut self, _desc: &TestDesc, _test_type: &str) -> io::Result<()> {
+        Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!"))
+    }
+
+    fn write_discovery_finish(&mut self, _state: &ConsoleTestDiscoveryState) -> io::Result<()> {
+        Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!"))
+    }
+
     fn write_run_start(
         &mut self,
         _test_count: usize,
diff --git a/library/test/src/formatters/mod.rs b/library/test/src/formatters/mod.rs
index cb67b6491a3..bc6ffebc1d3 100644
--- a/library/test/src/formatters/mod.rs
+++ b/library/test/src/formatters/mod.rs
@@ -1,7 +1,7 @@
 use std::{io, io::prelude::Write};
 
 use crate::{
-    console::ConsoleTestState,
+    console::{ConsoleTestDiscoveryState, ConsoleTestState},
     test_result::TestResult,
     time,
     types::{TestDesc, TestName},
@@ -18,6 +18,10 @@ pub(crate) use self::pretty::PrettyFormatter;
 pub(crate) use self::terse::TerseFormatter;
 
 pub(crate) trait OutputFormatter {
+    fn write_discovery_start(&mut self) -> io::Result<()>;
+    fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()>;
+    fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()>;
+
     fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()>;
     fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()>;
     fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>;
diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs
index 247778e515f..22654a3400b 100644
--- a/library/test/src/formatters/pretty.rs
+++ b/library/test/src/formatters/pretty.rs
@@ -3,7 +3,7 @@ use std::{io, io::prelude::Write};
 use super::OutputFormatter;
 use crate::{
     bench::fmt_bench_samples,
-    console::{ConsoleTestState, OutputLocation},
+    console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation},
     term,
     test_result::TestResult,
     time,
@@ -181,6 +181,33 @@ impl<T: Write> PrettyFormatter<T> {
 }
 
 impl<T: Write> OutputFormatter for PrettyFormatter<T> {
+    fn write_discovery_start(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+
+    fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> {
+        self.write_plain(format!("{}: {test_type}\n", desc.name))
+    }
+
+    fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()> {
+        fn plural(count: usize, s: &str) -> String {
+            match count {
+                1 => format!("1 {s}"),
+                n => format!("{n} {s}s"),
+            }
+        }
+
+        if state.tests != 0 || state.benchmarks != 0 {
+            self.write_plain("\n")?;
+        }
+
+        self.write_plain(format!(
+            "{}, {}\n",
+            plural(state.tests, "test"),
+            plural(state.benchmarks, "benchmark")
+        ))
+    }
+
     fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> {
         let noun = if test_count != 1 { "tests" } else { "test" };
         let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed {
diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs
index a431acfbc27..2931ca6ead0 100644
--- a/library/test/src/formatters/terse.rs
+++ b/library/test/src/formatters/terse.rs
@@ -3,7 +3,7 @@ use std::{io, io::prelude::Write};
 use super::OutputFormatter;
 use crate::{
     bench::fmt_bench_samples,
-    console::{ConsoleTestState, OutputLocation},
+    console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation},
     term,
     test_result::TestResult,
     time,
@@ -167,6 +167,18 @@ impl<T: Write> TerseFormatter<T> {
 }
 
 impl<T: Write> OutputFormatter for TerseFormatter<T> {
+    fn write_discovery_start(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+
+    fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> {
+        self.write_plain(format!("{}: {test_type}\n", desc.name))
+    }
+
+    fn write_discovery_finish(&mut self, _state: &ConsoleTestDiscoveryState) -> io::Result<()> {
+        Ok(())
+    }
+
     fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> {
         self.total_test_count = test_count;
         let noun = if test_count != 1 { "tests" } else { "test" };
diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs
index 44776fb0a31..5ffdbf73fbf 100644
--- a/library/test/src/tests.rs
+++ b/library/test/src/tests.rs
@@ -63,6 +63,16 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
                 name: StaticTestName("1"),
                 ignore: true,
                 ignore_message: None,
+                #[cfg(not(bootstrap))]
+                source_file: "",
+                #[cfg(not(bootstrap))]
+                start_line: 0,
+                #[cfg(not(bootstrap))]
+                start_col: 0,
+                #[cfg(not(bootstrap))]
+                end_line: 0,
+                #[cfg(not(bootstrap))]
+                end_col: 0,
                 should_panic: ShouldPanic::No,
                 compile_fail: false,
                 no_run: false,
@@ -75,6 +85,16 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
                 name: StaticTestName("2"),
                 ignore: false,
                 ignore_message: None,
+                #[cfg(not(bootstrap))]
+                source_file: "",
+                #[cfg(not(bootstrap))]
+                start_line: 0,
+                #[cfg(not(bootstrap))]
+                start_col: 0,
+                #[cfg(not(bootstrap))]
+                end_line: 0,
+                #[cfg(not(bootstrap))]
+                end_col: 0,
                 should_panic: ShouldPanic::No,
                 compile_fail: false,
                 no_run: false,
@@ -95,6 +115,16 @@ pub fn do_not_run_ignored_tests() {
             name: StaticTestName("whatever"),
             ignore: true,
             ignore_message: None,
+            #[cfg(not(bootstrap))]
+            source_file: "",
+            #[cfg(not(bootstrap))]
+            start_line: 0,
+            #[cfg(not(bootstrap))]
+            start_col: 0,
+            #[cfg(not(bootstrap))]
+            end_line: 0,
+            #[cfg(not(bootstrap))]
+            end_col: 0,
             should_panic: ShouldPanic::No,
             compile_fail: false,
             no_run: false,
@@ -118,6 +148,16 @@ pub fn ignored_tests_result_in_ignored() {
             name: StaticTestName("whatever"),
             ignore: true,
             ignore_message: None,
+            #[cfg(not(bootstrap))]
+            source_file: "",
+            #[cfg(not(bootstrap))]
+            start_line: 0,
+            #[cfg(not(bootstrap))]
+            start_col: 0,
+            #[cfg(not(bootstrap))]
+            end_line: 0,
+            #[cfg(not(bootstrap))]
+            end_col: 0,
             should_panic: ShouldPanic::No,
             compile_fail: false,
             no_run: false,
@@ -143,6 +183,16 @@ fn test_should_panic() {
             name: StaticTestName("whatever"),
             ignore: false,
             ignore_message: None,
+            #[cfg(not(bootstrap))]
+            source_file: "",
+            #[cfg(not(bootstrap))]
+            start_line: 0,
+            #[cfg(not(bootstrap))]
+            start_col: 0,
+            #[cfg(not(bootstrap))]
+            end_line: 0,
+            #[cfg(not(bootstrap))]
+            end_col: 0,
             should_panic: ShouldPanic::Yes,
             compile_fail: false,
             no_run: false,
@@ -168,6 +218,16 @@ fn test_should_panic_good_message() {
             name: StaticTestName("whatever"),
             ignore: false,
             ignore_message: None,
+            #[cfg(not(bootstrap))]
+            source_file: "",
+            #[cfg(not(bootstrap))]
+            start_line: 0,
+            #[cfg(not(bootstrap))]
+            start_col: 0,
+            #[cfg(not(bootstrap))]
+            end_line: 0,
+            #[cfg(not(bootstrap))]
+            end_col: 0,
             should_panic: ShouldPanic::YesWithMessage("error message"),
             compile_fail: false,
             no_run: false,
@@ -198,6 +258,16 @@ fn test_should_panic_bad_message() {
             name: StaticTestName("whatever"),
             ignore: false,
             ignore_message: None,
+            #[cfg(not(bootstrap))]
+            source_file: "",
+            #[cfg(not(bootstrap))]
+            start_line: 0,
+            #[cfg(not(bootstrap))]
+            start_col: 0,
+            #[cfg(not(bootstrap))]
+            end_line: 0,
+            #[cfg(not(bootstrap))]
+            end_col: 0,
             should_panic: ShouldPanic::YesWithMessage(expected),
             compile_fail: false,
             no_run: false,
@@ -232,6 +302,16 @@ fn test_should_panic_non_string_message_type() {
             name: StaticTestName("whatever"),
             ignore: false,
             ignore_message: None,
+            #[cfg(not(bootstrap))]
+            source_file: "",
+            #[cfg(not(bootstrap))]
+            start_line: 0,
+            #[cfg(not(bootstrap))]
+            start_col: 0,
+            #[cfg(not(bootstrap))]
+            end_line: 0,
+            #[cfg(not(bootstrap))]
+            end_col: 0,
             should_panic: ShouldPanic::YesWithMessage(expected),
             compile_fail: false,
             no_run: false,
@@ -260,6 +340,16 @@ fn test_should_panic_but_succeeds() {
                 name: StaticTestName("whatever"),
                 ignore: false,
                 ignore_message: None,
+                #[cfg(not(bootstrap))]
+                source_file: "",
+                #[cfg(not(bootstrap))]
+                start_line: 0,
+                #[cfg(not(bootstrap))]
+                start_col: 0,
+                #[cfg(not(bootstrap))]
+                end_line: 0,
+                #[cfg(not(bootstrap))]
+                end_col: 0,
                 should_panic,
                 compile_fail: false,
                 no_run: false,
@@ -288,6 +378,16 @@ fn report_time_test_template(report_time: bool) -> Option<TestExecTime> {
             name: StaticTestName("whatever"),
             ignore: false,
             ignore_message: None,
+            #[cfg(not(bootstrap))]
+            source_file: "",
+            #[cfg(not(bootstrap))]
+            start_line: 0,
+            #[cfg(not(bootstrap))]
+            start_col: 0,
+            #[cfg(not(bootstrap))]
+            end_line: 0,
+            #[cfg(not(bootstrap))]
+            end_col: 0,
             should_panic: ShouldPanic::No,
             compile_fail: false,
             no_run: false,
@@ -325,6 +425,16 @@ fn time_test_failure_template(test_type: TestType) -> TestResult {
             name: StaticTestName("whatever"),
             ignore: false,
             ignore_message: None,
+            #[cfg(not(bootstrap))]
+            source_file: "",
+            #[cfg(not(bootstrap))]
+            start_line: 0,
+            #[cfg(not(bootstrap))]
+            start_col: 0,
+            #[cfg(not(bootstrap))]
+            end_line: 0,
+            #[cfg(not(bootstrap))]
+            end_col: 0,
             should_panic: ShouldPanic::No,
             compile_fail: false,
             no_run: false,
@@ -364,6 +474,16 @@ fn typed_test_desc(test_type: TestType) -> TestDesc {
         name: StaticTestName("whatever"),
         ignore: false,
         ignore_message: None,
+        #[cfg(not(bootstrap))]
+        source_file: "",
+        #[cfg(not(bootstrap))]
+        start_line: 0,
+        #[cfg(not(bootstrap))]
+        start_col: 0,
+        #[cfg(not(bootstrap))]
+        end_line: 0,
+        #[cfg(not(bootstrap))]
+        end_col: 0,
         should_panic: ShouldPanic::No,
         compile_fail: false,
         no_run: false,
@@ -476,6 +596,16 @@ pub fn exclude_should_panic_option() {
             name: StaticTestName("3"),
             ignore: false,
             ignore_message: None,
+            #[cfg(not(bootstrap))]
+            source_file: "",
+            #[cfg(not(bootstrap))]
+            start_line: 0,
+            #[cfg(not(bootstrap))]
+            start_col: 0,
+            #[cfg(not(bootstrap))]
+            end_line: 0,
+            #[cfg(not(bootstrap))]
+            end_col: 0,
             should_panic: ShouldPanic::Yes,
             compile_fail: false,
             no_run: false,
@@ -500,6 +630,16 @@ pub fn exact_filter_match() {
                     name: StaticTestName(name),
                     ignore: false,
                     ignore_message: None,
+                    #[cfg(not(bootstrap))]
+                    source_file: "",
+                    #[cfg(not(bootstrap))]
+                    start_line: 0,
+                    #[cfg(not(bootstrap))]
+                    start_col: 0,
+                    #[cfg(not(bootstrap))]
+                    end_line: 0,
+                    #[cfg(not(bootstrap))]
+                    end_col: 0,
                     should_panic: ShouldPanic::No,
                     compile_fail: false,
                     no_run: false,
@@ -591,6 +731,16 @@ fn sample_tests() -> Vec<TestDescAndFn> {
                 name: DynTestName((*name).clone()),
                 ignore: false,
                 ignore_message: None,
+                #[cfg(not(bootstrap))]
+                source_file: "",
+                #[cfg(not(bootstrap))]
+                start_line: 0,
+                #[cfg(not(bootstrap))]
+                start_col: 0,
+                #[cfg(not(bootstrap))]
+                end_line: 0,
+                #[cfg(not(bootstrap))]
+                end_col: 0,
                 should_panic: ShouldPanic::No,
                 compile_fail: false,
                 no_run: false,
@@ -720,6 +870,16 @@ pub fn test_bench_no_iter() {
         name: StaticTestName("f"),
         ignore: false,
         ignore_message: None,
+        #[cfg(not(bootstrap))]
+        source_file: "",
+        #[cfg(not(bootstrap))]
+        start_line: 0,
+        #[cfg(not(bootstrap))]
+        start_col: 0,
+        #[cfg(not(bootstrap))]
+        end_line: 0,
+        #[cfg(not(bootstrap))]
+        end_col: 0,
         should_panic: ShouldPanic::No,
         compile_fail: false,
         no_run: false,
@@ -743,6 +903,16 @@ pub fn test_bench_iter() {
         name: StaticTestName("f"),
         ignore: false,
         ignore_message: None,
+        #[cfg(not(bootstrap))]
+        source_file: "",
+        #[cfg(not(bootstrap))]
+        start_line: 0,
+        #[cfg(not(bootstrap))]
+        start_col: 0,
+        #[cfg(not(bootstrap))]
+        end_line: 0,
+        #[cfg(not(bootstrap))]
+        end_col: 0,
         should_panic: ShouldPanic::No,
         compile_fail: false,
         no_run: false,
@@ -759,6 +929,16 @@ fn should_sort_failures_before_printing_them() {
         name: StaticTestName("a"),
         ignore: false,
         ignore_message: None,
+        #[cfg(not(bootstrap))]
+        source_file: "",
+        #[cfg(not(bootstrap))]
+        start_line: 0,
+        #[cfg(not(bootstrap))]
+        start_col: 0,
+        #[cfg(not(bootstrap))]
+        end_line: 0,
+        #[cfg(not(bootstrap))]
+        end_col: 0,
         should_panic: ShouldPanic::No,
         compile_fail: false,
         no_run: false,
@@ -769,6 +949,16 @@ fn should_sort_failures_before_printing_them() {
         name: StaticTestName("b"),
         ignore: false,
         ignore_message: None,
+        #[cfg(not(bootstrap))]
+        source_file: "",
+        #[cfg(not(bootstrap))]
+        start_line: 0,
+        #[cfg(not(bootstrap))]
+        start_col: 0,
+        #[cfg(not(bootstrap))]
+        end_line: 0,
+        #[cfg(not(bootstrap))]
+        end_col: 0,
         should_panic: ShouldPanic::No,
         compile_fail: false,
         no_run: false,
@@ -816,6 +1006,16 @@ fn test_dyn_bench_returning_err_fails_when_run_as_test() {
             name: StaticTestName("whatever"),
             ignore: false,
             ignore_message: None,
+            #[cfg(not(bootstrap))]
+            source_file: "",
+            #[cfg(not(bootstrap))]
+            start_line: 0,
+            #[cfg(not(bootstrap))]
+            start_col: 0,
+            #[cfg(not(bootstrap))]
+            end_line: 0,
+            #[cfg(not(bootstrap))]
+            end_col: 0,
             should_panic: ShouldPanic::No,
             compile_fail: false,
             no_run: false,
diff --git a/library/test/src/types.rs b/library/test/src/types.rs
index 6f2e033095a..8d4e204c8ac 100644
--- a/library/test/src/types.rs
+++ b/library/test/src/types.rs
@@ -119,6 +119,16 @@ pub struct TestDesc {
     pub name: TestName,
     pub ignore: bool,
     pub ignore_message: Option<&'static str>,
+    #[cfg(not(bootstrap))]
+    pub source_file: &'static str,
+    #[cfg(not(bootstrap))]
+    pub start_line: usize,
+    #[cfg(not(bootstrap))]
+    pub start_col: usize,
+    #[cfg(not(bootstrap))]
+    pub end_line: usize,
+    #[cfg(not(bootstrap))]
+    pub end_col: usize,
     pub should_panic: options::ShouldPanic,
     pub compile_fail: bool,
     pub no_run: bool,
diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md
index 54d0d8a8ec2..654e03d0c3c 100644
--- a/src/bootstrap/CHANGELOG.md
+++ b/src/bootstrap/CHANGELOG.md
@@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - If you have Rust already installed, `x.py` will now infer the host target
   from the default rust toolchain. [#78513](https://github.com/rust-lang/rust/pull/78513)
 - Add options for enabling overflow checks, one for std (`overflow-checks-std`) and one for everything else (`overflow-checks`). Both default to false.
+- Add llvm option `enable-warnings` to have control on llvm compilation warnings. Default to false.
 
 
 ## [Version 2] - 2020-09-25
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index e861d520c53..27236e191fd 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -12,6 +12,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
 name = "autocfg"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -36,6 +47,7 @@ dependencies = [
 name = "bootstrap"
 version = "0.0.0"
 dependencies = [
+ "atty",
  "build_helper",
  "cc",
  "cmake",
@@ -55,9 +67,10 @@ dependencies = [
  "sha2",
  "sysinfo",
  "tar",
+ "termcolor",
  "toml",
  "walkdir",
- "winapi",
+ "windows",
  "xz2",
 ]
 
@@ -637,6 +650,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "termcolor"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
 name = "thread_local"
 version = "1.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -721,6 +743,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
+name = "windows"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
 name = "windows-sys"
 version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -736,46 +767,61 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
 
 [[package]]
 name = "xattr"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index afe3fc1741b..5c659800bdb 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -30,6 +30,7 @@ path = "bin/sccache-plus-cl.rs"
 test = false
 
 [dependencies]
+atty = "0.2.14"
 build_helper = { path = "../tools/build_helper" }
 cmake = "0.1.38"
 filetime = "0.2"
@@ -45,6 +46,7 @@ serde_derive = "1.0.137"
 serde_json = "1.0.2"
 sha2 = "0.10"
 tar = "0.4"
+termcolor = "1.2.0"
 toml = "0.5"
 ignore = "0.4.10"
 opener = "0.5"
@@ -59,18 +61,20 @@ sysinfo = { version = "0.26.0", optional = true }
 [target.'cfg(not(target_os = "solaris"))'.dependencies]
 fd-lock = "3.0.8"
 
-[target.'cfg(windows)'.dependencies.winapi]
-version = "0.3"
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
 features = [
-    "fileapi",
-    "ioapiset",
-    "jobapi2",
-    "handleapi",
-    "winioctl",
-    "psapi",
-    "impl-default",
-    "timezoneapi",
-    "winbase",
+    "Win32_Foundation",
+    "Win32_Security",
+    "Win32_Storage_FileSystem",
+    "Win32_System_Diagnostics_Debug",
+    "Win32_System_IO",
+    "Win32_System_Ioctl",
+    "Win32_System_JobObjects",
+    "Win32_System_ProcessStatus",
+    "Win32_System_SystemServices",
+    "Win32_System_Threading",
+    "Win32_System_Time",
 ]
 
 [dev-dependencies]
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 9611c866df5..040fec3615b 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -281,41 +281,49 @@ fn format_rusage_data(_child: Child) -> Option<String> {
 #[cfg(windows)]
 fn format_rusage_data(child: Child) -> Option<String> {
     use std::os::windows::io::AsRawHandle;
-    use winapi::um::{processthreadsapi, psapi, timezoneapi};
-    let handle = child.as_raw_handle();
-    macro_rules! try_bool {
-        ($e:expr) => {
-            if $e != 1 {
-                return None;
-            }
-        };
-    }
+
+    use windows::{
+        Win32::Foundation::HANDLE,
+        Win32::System::ProcessStatus::{
+            K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX,
+        },
+        Win32::System::Threading::GetProcessTimes,
+        Win32::System::Time::FileTimeToSystemTime,
+    };
+
+    let handle = HANDLE(child.as_raw_handle() as isize);
 
     let mut user_filetime = Default::default();
     let mut user_time = Default::default();
     let mut kernel_filetime = Default::default();
     let mut kernel_time = Default::default();
-    let mut memory_counters = psapi::PROCESS_MEMORY_COUNTERS::default();
+    let mut memory_counters = PROCESS_MEMORY_COUNTERS::default();
 
     unsafe {
-        try_bool!(processthreadsapi::GetProcessTimes(
+        GetProcessTimes(
             handle,
             &mut Default::default(),
             &mut Default::default(),
             &mut kernel_filetime,
             &mut user_filetime,
-        ));
-        try_bool!(timezoneapi::FileTimeToSystemTime(&user_filetime, &mut user_time));
-        try_bool!(timezoneapi::FileTimeToSystemTime(&kernel_filetime, &mut kernel_time));
-
-        // Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process
-        // with the given handle and none of that process's children.
-        try_bool!(psapi::GetProcessMemoryInfo(
-            handle as _,
-            &mut memory_counters as *mut _ as _,
-            std::mem::size_of::<psapi::PROCESS_MEMORY_COUNTERS_EX>() as u32,
-        ));
+        )
+    }
+    .ok()
+    .ok()?;
+    unsafe { FileTimeToSystemTime(&user_filetime, &mut user_time) }.ok().ok()?;
+    unsafe { FileTimeToSystemTime(&kernel_filetime, &mut kernel_time) }.ok().ok()?;
+
+    // Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process
+    // with the given handle and none of that process's children.
+    unsafe {
+        K32GetProcessMemoryInfo(
+            handle,
+            &mut memory_counters,
+            std::mem::size_of::<PROCESS_MEMORY_COUNTERS_EX>() as u32,
+        )
     }
+    .ok()
+    .ok()?;
 
     // Guide on interpreting these numbers:
     // https://docs.microsoft.com/en-us/windows/win32/psapi/process-memory-usage-information
diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py
index 06ca3ce21b3..20bd71f06e9 100644
--- a/src/bootstrap/bootstrap_test.py
+++ b/src/bootstrap/bootstrap_test.py
@@ -11,6 +11,7 @@ import sys
 from shutil import rmtree
 
 import bootstrap
+import configure
 
 
 class VerifyTestCase(unittest.TestCase):
@@ -74,12 +75,50 @@ class ProgramOutOfDate(unittest.TestCase):
         self.assertFalse(self.build.program_out_of_date(self.rustc_stamp_path, self.key))
 
 
+class GenerateAndParseConfig(unittest.TestCase):
+    """Test that we can serialize and deserialize a config.toml file"""
+    def serialize_and_parse(self, args):
+        from io import StringIO
+
+        section_order, sections, targets = configure.parse_args(args)
+        buffer = StringIO()
+        configure.write_config_toml(buffer, section_order, targets, sections)
+        build = bootstrap.RustBuild()
+        build.config_toml = buffer.getvalue()
+
+        try:
+            import tomllib
+            # Verify this is actually valid TOML.
+            tomllib.loads(build.config_toml)
+        except ImportError:
+            print("warning: skipping TOML validation, need at least python 3.11", file=sys.stderr)
+        return build
+
+    def test_no_args(self):
+        build = self.serialize_and_parse([])
+        self.assertEqual(build.get_toml("changelog-seen"), '2')
+        self.assertIsNone(build.get_toml("llvm.download-ci-llvm"))
+
+    def test_set_section(self):
+        build = self.serialize_and_parse(["--set", "llvm.download-ci-llvm"])
+        self.assertEqual(build.get_toml("download-ci-llvm", section="llvm"), 'true')
+
+    def test_set_target(self):
+        build = self.serialize_and_parse(["--set", "target.x86_64-unknown-linux-gnu.cc=gcc"])
+        self.assertEqual(build.get_toml("cc", section="target.x86_64-unknown-linux-gnu"), 'gcc')
+
+    # Uncomment when #108928 is fixed.
+    # def test_set_top_level(self):
+    #     build = self.serialize_and_parse(["--set", "profile=compiler"])
+    #     self.assertEqual(build.get_toml("profile"), 'compiler')
+
 if __name__ == '__main__':
     SUITE = unittest.TestSuite()
     TEST_LOADER = unittest.TestLoader()
     SUITE.addTest(doctest.DocTestSuite(bootstrap))
     SUITE.addTests([
         TEST_LOADER.loadTestsFromTestCase(VerifyTestCase),
+        TEST_LOADER.loadTestsFromTestCase(GenerateAndParseConfig),
         TEST_LOADER.loadTestsFromTestCase(ProgramOutOfDate)])
 
     RUNNER = unittest.TextTestRunner(stream=sys.stdout, verbosity=2)
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index c68452db0af..83a6d0ad292 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1303,6 +1303,14 @@ impl<'a> Builder<'a> {
             }
         };
 
+        // By default, windows-rs depends on a native library that doesn't get copied into the
+        // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native
+        // library unnecessary. This can be removed when windows-rs enables raw-dylib
+        // unconditionally.
+        if let Mode::Rustc | Mode::ToolRustc = mode {
+            rustflags.arg("--cfg=windows_raw_dylib");
+        }
+
         if use_new_symbol_mangling {
             rustflags.arg("-Csymbol-mangling-version=v0");
         } else {
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 8b80dfc0f9b..54971af644c 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -339,6 +339,12 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
         ""
     };
 
+    // `libtest` uses this to know whether or not to support
+    // `-Zunstable-options`.
+    if !builder.unstable_features() {
+        cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");
+    }
+
     let mut features = String::new();
 
     // Cranelift doesn't support `asm`.
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index fc5aa8a245d..95625170478 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -87,6 +87,9 @@ pub struct Config {
     pub patch_binaries_for_nix: bool,
     pub stage0_metadata: Stage0Metadata,
 
+    pub stdout_is_tty: bool,
+    pub stderr_is_tty: bool,
+
     pub on_fail: Option<String>,
     pub stage: u32,
     pub keep_stage: Vec<u32>,
@@ -133,6 +136,7 @@ pub struct Config {
     pub llvm_allow_old_toolchain: bool,
     pub llvm_polly: bool,
     pub llvm_clang: bool,
+    pub llvm_enable_warnings: bool,
     pub llvm_from_ci: bool,
     pub llvm_build_config: HashMap<String, String>,
 
@@ -190,6 +194,7 @@ pub struct Config {
     pub dist_sign_folder: Option<PathBuf>,
     pub dist_upload_addr: Option<String>,
     pub dist_compression_formats: Option<Vec<String>>,
+    pub dist_compression_profile: String,
     pub dist_include_mingw_linker: bool,
 
     // libstd features
@@ -688,6 +693,7 @@ define_config! {
         allow_old_toolchain: Option<bool> = "allow-old-toolchain",
         polly: Option<bool> = "polly",
         clang: Option<bool> = "clang",
+        enable_warnings: Option<bool> = "enable-warnings",
         download_ci_llvm: Option<StringOrBool> = "download-ci-llvm",
         build_config: Option<HashMap<String, String>> = "build-config",
     }
@@ -701,6 +707,7 @@ define_config! {
         src_tarball: Option<bool> = "src-tarball",
         missing_tools: Option<bool> = "missing-tools",
         compression_formats: Option<Vec<String>> = "compression-formats",
+        compression_profile: Option<String> = "compression-profile",
         include_mingw_linker: Option<bool> = "include-mingw-linker",
     }
 }
@@ -819,6 +826,10 @@ impl Config {
         config.deny_warnings = true;
         config.bindir = "bin".into();
         config.dist_include_mingw_linker = true;
+        config.dist_compression_profile = "fast".into();
+
+        config.stdout_is_tty = atty::is(atty::Stream::Stdout);
+        config.stderr_is_tty = atty::is(atty::Stream::Stderr);
 
         // set by build.rs
         config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
@@ -1151,6 +1162,11 @@ impl Config {
             config.rust_profile_generate = flags.rust_profile_generate;
         }
 
+        // rust_info must be set before is_ci_llvm_available() is called.
+        let default = config.channel == "dev";
+        config.ignore_git = ignore_git.unwrap_or(default);
+        config.rust_info = GitInfo::new(config.ignore_git, &config.src);
+
         if let Some(llvm) = toml.llvm {
             match llvm.ccache {
                 Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()),
@@ -1184,6 +1200,7 @@ impl Config {
             config.llvm_allow_old_toolchain = llvm.allow_old_toolchain.unwrap_or(false);
             config.llvm_polly = llvm.polly.unwrap_or(false);
             config.llvm_clang = llvm.clang.unwrap_or(false);
+            config.llvm_enable_warnings = llvm.enable_warnings.unwrap_or(false);
             config.llvm_build_config = llvm.build_config.clone().unwrap_or(Default::default());
 
             let asserts = llvm_assertions.unwrap_or(false);
@@ -1300,6 +1317,7 @@ impl Config {
             config.dist_sign_folder = t.sign_folder.map(PathBuf::from);
             config.dist_upload_addr = t.upload_addr;
             config.dist_compression_formats = t.compression_formats;
+            set(&mut config.dist_compression_profile, t.compression_profile);
             set(&mut config.rust_dist_src, t.src_tarball);
             set(&mut config.missing_tools, t.missing_tools);
             set(&mut config.dist_include_mingw_linker, t.include_mingw_linker)
@@ -1343,10 +1361,6 @@ impl Config {
         config.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools);
         config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(0);
 
-        let default = config.channel == "dev";
-        config.ignore_git = ignore_git.unwrap_or(default);
-        config.rust_info = GitInfo::new(config.ignore_git, &config.src);
-
         let download_rustc = config.download_rustc_commit.is_some();
         // See https://github.com/rust-lang/compiler-team/issues/326
         config.stage = match config.cmd {
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index b326ae402aa..abd28b4005d 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -205,77 +205,78 @@ if '--help' in sys.argv or '-h' in sys.argv:
 
 # Parse all command line arguments into one of these three lists, handling
 # boolean and value-based options separately
-unknown_args = []
-need_value_args = []
-known_args = {}
-
-p("processing command line")
-i = 1
-while i < len(sys.argv):
-    arg = sys.argv[i]
-    i += 1
-    if not arg.startswith('--'):
-        unknown_args.append(arg)
-        continue
-
-    found = False
-    for option in options:
-        value = None
-        if option.value:
-            keyval = arg[2:].split('=', 1)
-            key = keyval[0]
-            if option.name != key:
-                continue
+def parse_args(args):
+    unknown_args = []
+    need_value_args = []
+    known_args = {}
+
+    i = 0
+    while i < len(args):
+        arg = args[i]
+        i += 1
+        if not arg.startswith('--'):
+            unknown_args.append(arg)
+            continue
 
-            if len(keyval) > 1:
-                value = keyval[1]
-            elif i < len(sys.argv):
-                value = sys.argv[i]
-                i += 1
-            else:
-                need_value_args.append(arg)
-                continue
-        else:
-            if arg[2:] == 'enable-' + option.name:
-                value = True
-            elif arg[2:] == 'disable-' + option.name:
-                value = False
+        found = False
+        for option in options:
+            value = None
+            if option.value:
+                keyval = arg[2:].split('=', 1)
+                key = keyval[0]
+                if option.name != key:
+                    continue
+
+                if len(keyval) > 1:
+                    value = keyval[1]
+                elif i < len(args):
+                    value = args[i]
+                    i += 1
+                else:
+                    need_value_args.append(arg)
+                    continue
             else:
-                continue
+                if arg[2:] == 'enable-' + option.name:
+                    value = True
+                elif arg[2:] == 'disable-' + option.name:
+                    value = False
+                else:
+                    continue
+
+            found = True
+            if option.name not in known_args:
+                known_args[option.name] = []
+            known_args[option.name].append((option, value))
+            break
+
+        if not found:
+            unknown_args.append(arg)
+
+    # Note: here and a few other places, we use [-1] to apply the *last* value
+    # passed.  But if option-checking is enabled, then the known_args loop will
+    # also assert that options are only passed once.
+    option_checking = ('option-checking' not in known_args
+                    or known_args['option-checking'][-1][1])
+    if option_checking:
+        if len(unknown_args) > 0:
+            err("Option '" + unknown_args[0] + "' is not recognized")
+        if len(need_value_args) > 0:
+            err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0]))
+
+    config = {}
+
+    set('build.configure-args', sys.argv[1:], config)
+    apply_args(known_args, option_checking, config)
+    return parse_example_config(known_args, config)
 
-        found = True
-        if option.name not in known_args:
-            known_args[option.name] = []
-        known_args[option.name].append((option, value))
-        break
-
-    if not found:
-        unknown_args.append(arg)
-p("")
-
-# Note: here and a few other places, we use [-1] to apply the *last* value
-# passed.  But if option-checking is enabled, then the known_args loop will
-# also assert that options are only passed once.
-option_checking = ('option-checking' not in known_args
-                   or known_args['option-checking'][-1][1])
-if option_checking:
-    if len(unknown_args) > 0:
-        err("Option '" + unknown_args[0] + "' is not recognized")
-    if len(need_value_args) > 0:
-        err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0]))
-
-# Parse all known arguments into a configuration structure that reflects the
-# TOML we're going to write out
-config = {}
-
-
-def build():
+
+def build(known_args):
     if 'build' in known_args:
         return known_args['build'][-1][1]
     return bootstrap.default_build_triple(verbose=False)
 
 
-def set(key, value):
+def set(key, value, config):
     if isinstance(value, list):
         # Remove empty values, which value.split(',') tends to generate.
         value = [v for v in value if v]
@@ -297,75 +298,76 @@ def set(key, value):
             arr = arr[part]
 
 
-for key in known_args:
-    # The `set` option is special and can be passed a bunch of times
-    if key == 'set':
-        for option, value in known_args[key]:
-            keyval = value.split('=', 1)
-            if len(keyval) == 1 or keyval[1] == "true":
-                value = True
-            elif keyval[1] == "false":
-                value = False
-            else:
-                value = keyval[1]
-            set(keyval[0], value)
-        continue
-
-    # Ensure each option is only passed once
-    arr = known_args[key]
-    if option_checking and len(arr) > 1:
-        err("Option '{}' provided more than once".format(key))
-    option, value = arr[-1]
-
-    # If we have a clear avenue to set our value in rustbuild, do so
-    if option.rustbuild is not None:
-        set(option.rustbuild, value)
-        continue
-
-    # Otherwise we're a "special" option and need some extra handling, so do
-    # that here.
-    if option.name == 'sccache':
-        set('llvm.ccache', 'sccache')
-    elif option.name == 'local-rust':
-        for path in os.environ['PATH'].split(os.pathsep):
-            if os.path.exists(path + '/rustc'):
-                set('build.rustc', path + '/rustc')
-                break
-        for path in os.environ['PATH'].split(os.pathsep):
-            if os.path.exists(path + '/cargo'):
-                set('build.cargo', path + '/cargo')
-                break
-    elif option.name == 'local-rust-root':
-        set('build.rustc', value + '/bin/rustc')
-        set('build.cargo', value + '/bin/cargo')
-    elif option.name == 'llvm-root':
-        set('target.{}.llvm-config'.format(build()), value + '/bin/llvm-config')
-    elif option.name == 'llvm-config':
-        set('target.{}.llvm-config'.format(build()), value)
-    elif option.name == 'llvm-filecheck':
-        set('target.{}.llvm-filecheck'.format(build()), value)
-    elif option.name == 'tools':
-        set('build.tools', value.split(','))
-    elif option.name == 'codegen-backends':
-        set('rust.codegen-backends', value.split(','))
-    elif option.name == 'host':
-        set('build.host', value.split(','))
-    elif option.name == 'target':
-        set('build.target', value.split(','))
-    elif option.name == 'full-tools':
-        set('rust.codegen-backends', ['llvm'])
-        set('rust.lld', True)
-        set('rust.llvm-tools', True)
-        set('build.extended', True)
-    elif option.name == 'option-checking':
-        # this was handled above
-        pass
-    elif option.name == 'dist-compression-formats':
-        set('dist.compression-formats', value.split(','))
-    else:
-        raise RuntimeError("unhandled option {}".format(option.name))
+def apply_args(known_args, option_checking, config):
+    for key in known_args:
+        # The `set` option is special and can be passed a bunch of times
+        if key == 'set':
+            for option, value in known_args[key]:
+                keyval = value.split('=', 1)
+                if len(keyval) == 1 or keyval[1] == "true":
+                    value = True
+                elif keyval[1] == "false":
+                    value = False
+                else:
+                    value = keyval[1]
+                set(keyval[0], value, config)
+            continue
 
-set('build.configure-args', sys.argv[1:])
+        # Ensure each option is only passed once
+        arr = known_args[key]
+        if option_checking and len(arr) > 1:
+            err("Option '{}' provided more than once".format(key))
+        option, value = arr[-1]
+
+        # If we have a clear avenue to set our value in rustbuild, do so
+        if option.rustbuild is not None:
+            set(option.rustbuild, value, config)
+            continue
+
+        # Otherwise we're a "special" option and need some extra handling, so do
+        # that here.
+        build_triple = build(known_args)
+
+        if option.name == 'sccache':
+            set('llvm.ccache', 'sccache', config)
+        elif option.name == 'local-rust':
+            for path in os.environ['PATH'].split(os.pathsep):
+                if os.path.exists(path + '/rustc'):
+                    set('build.rustc', path + '/rustc', config)
+                    break
+            for path in os.environ['PATH'].split(os.pathsep):
+                if os.path.exists(path + '/cargo'):
+                    set('build.cargo', path + '/cargo', config)
+                    break
+        elif option.name == 'local-rust-root':
+            set('build.rustc', value + '/bin/rustc', config)
+            set('build.cargo', value + '/bin/cargo', config)
+        elif option.name == 'llvm-root':
+            set('target.{}.llvm-config'.format(build_triple), value + '/bin/llvm-config', config)
+        elif option.name == 'llvm-config':
+            set('target.{}.llvm-config'.format(build_triple), value, config)
+        elif option.name == 'llvm-filecheck':
+            set('target.{}.llvm-filecheck'.format(build_triple), value, config)
+        elif option.name == 'tools':
+            set('build.tools', value.split(','), config)
+        elif option.name == 'codegen-backends':
+            set('rust.codegen-backends', value.split(','), config)
+        elif option.name == 'host':
+            set('build.host', value.split(','), config)
+        elif option.name == 'target':
+            set('build.target', value.split(','), config)
+        elif option.name == 'full-tools':
+            set('rust.codegen-backends', ['llvm'], config)
+            set('rust.lld', True, config)
+            set('rust.llvm-tools', True, config)
+            set('build.extended', True, config)
+        elif option.name == 'option-checking':
+            # this was handled above
+            pass
+        elif option.name == 'dist-compression-formats':
+            set('dist.compression-formats', value.split(','), config)
+        else:
+            raise RuntimeError("unhandled option {}".format(option.name))
 
 # "Parse" the `config.example.toml` file into the various sections, and we'll
 # use this as a template of a `config.toml` to write out which preserves
@@ -373,46 +375,50 @@ set('build.configure-args', sys.argv[1:])
 #
 # Note that the `target` section is handled separately as we'll duplicate it
 # per configured target, so there's a bit of special handling for that here.
-sections = {}
-cur_section = None
-sections[None] = []
-section_order = [None]
-targets = {}
-top_level_keys = []
-
-for line in open(rust_dir + '/config.example.toml').read().split("\n"):
-    if cur_section == None:
-        if line.count('=') == 1:
-            top_level_key = line.split('=')[0]
-            top_level_key = top_level_key.strip(' #')
-            top_level_keys.append(top_level_key)
-    if line.startswith('['):
-        cur_section = line[1:-1]
-        if cur_section.startswith('target'):
-            cur_section = 'target'
-        elif '.' in cur_section:
-            raise RuntimeError("don't know how to deal with section: {}".format(cur_section))
-        sections[cur_section] = [line]
-        section_order.append(cur_section)
-    else:
-        sections[cur_section].append(line)
-
-# Fill out the `targets` array by giving all configured targets a copy of the
-# `target` section we just loaded from the example config
-configured_targets = [build()]
-if 'build' in config:
-    if 'host' in config['build']:
-        configured_targets += config['build']['host']
-    if 'target' in config['build']:
-        configured_targets += config['build']['target']
-if 'target' in config:
-    for target in config['target']:
-        configured_targets.append(target)
-for target in configured_targets:
-    targets[target] = sections['target'][:]
-    # For `.` to be valid TOML, it needs to be quoted. But `bootstrap.py` doesn't use a proper TOML parser and fails to parse the target.
-    # Avoid using quotes unless it's necessary.
-    targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target)
+def parse_example_config(known_args, config):
+    sections = {}
+    cur_section = None
+    sections[None] = []
+    section_order = [None]
+    targets = {}
+    top_level_keys = []
+
+    for line in open(rust_dir + '/config.example.toml').read().split("\n"):
+        if cur_section == None:
+            if line.count('=') == 1:
+                top_level_key = line.split('=')[0]
+                top_level_key = top_level_key.strip(' #')
+                top_level_keys.append(top_level_key)
+        if line.startswith('['):
+            cur_section = line[1:-1]
+            if cur_section.startswith('target'):
+                cur_section = 'target'
+            elif '.' in cur_section:
+                raise RuntimeError("don't know how to deal with section: {}".format(cur_section))
+            sections[cur_section] = [line]
+            section_order.append(cur_section)
+        else:
+            sections[cur_section].append(line)
+
+    # Fill out the `targets` array by giving all configured targets a copy of the
+    # `target` section we just loaded from the example config
+    configured_targets = [build(known_args)]
+    if 'build' in config:
+        if 'host' in config['build']:
+            configured_targets += config['build']['host']
+        if 'target' in config['build']:
+            configured_targets += config['build']['target']
+    if 'target' in config:
+        for target in config['target']:
+            configured_targets.append(target)
+    for target in configured_targets:
+        targets[target] = sections['target'][:]
+        # For `.` to be valid TOML, it needs to be quoted. But `bootstrap.py` doesn't use a proper TOML parser and fails to parse the target.
+        # Avoid using quotes unless it's necessary.
+        targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target)
+
+    configure_file(sections, top_level_keys, targets, config)
+    return section_order, sections, targets
 
 
 def is_number(value):
@@ -475,17 +481,20 @@ def configure_top_level_key(lines, top_level_key, value):
     raise RuntimeError("failed to find config line for {}".format(top_level_key))
 
 
-for section_key, section_config in config.items():
-    if section_key not in sections and section_key not in top_level_keys:
-        raise RuntimeError("config key {} not in sections or top_level_keys".format(section_key))
-    if section_key in top_level_keys:
-        configure_top_level_key(sections[None], section_key, section_config)
+# Modify `sections` to reflect the parsed arguments and example configs.
+def configure_file(sections, top_level_keys, targets, config):
+    for section_key, section_config in config.items():
+        if section_key not in sections and section_key not in top_level_keys:
+            raise RuntimeError("config key {} not in sections or top_level_keys".format(section_key))
+        if section_key in top_level_keys:
+            configure_top_level_key(sections[None], section_key, section_config)
+
+        elif  section_key == 'target':
+            for target in section_config:
+                configure_section(targets[target], section_config[target])
+        else:
+            configure_section(sections[section_key], section_config)
 
-    elif  section_key == 'target':
-        for target in section_config:
-            configure_section(targets[target], section_config[target])
-    else:
-        configure_section(sections[section_key], section_config)
 
 def write_uncommented(target, f):
     block = []
@@ -503,24 +512,36 @@ def write_uncommented(target, f):
         is_comment = is_comment and line.startswith('#')
     return f
 
-# Now that we've built up our `config.toml`, write it all out in the same
-# order that we read it in.
-p("")
-p("writing `config.toml` in current directory")
-with bootstrap.output('config.toml') as f:
+
+def write_config_toml(writer, section_order, targets, sections):
     for section in section_order:
         if section == 'target':
             for target in targets:
-                f = write_uncommented(targets[target], f)
+                writer = write_uncommented(targets[target], writer)
         else:
-            f = write_uncommented(sections[section], f)
-
-with bootstrap.output('Makefile') as f:
-    contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in')
-    contents = open(contents).read()
-    contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/')
-    contents = contents.replace("$(CFG_PYTHON)", sys.executable)
-    f.write(contents)
-
-p("")
-p("run `python {}/x.py --help`".format(rust_dir))
+            writer = write_uncommented(sections[section], writer)
+
+
+if __name__ == "__main__":
+    p("processing command line")
+    # Parse all known arguments into a configuration structure that reflects the
+    # TOML we're going to write out
+    p("")
+    section_order, sections, targets = parse_args(sys.argv[1:])
+
+    # Now that we've built up our `config.toml`, write it all out in the same
+    # order that we read it in.
+    p("")
+    p("writing `config.toml` in current directory")
+    with bootstrap.output('config.toml') as f:
+        write_config_toml(f, section_order, targets, sections)
+
+    with bootstrap.output('Makefile') as f:
+        contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in')
+        contents = open(contents).read()
+        contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/')
+        contents = contents.replace("$(CFG_PYTHON)", sys.executable)
+        f.write(contents)
+
+    p("")
+    p("run `python {}/x.py --help`".format(rust_dir))
diff --git a/src/bootstrap/defaults/config.codegen.toml b/src/bootstrap/defaults/config.codegen.toml
index eb2afa555f1..20b2699c761 100644
--- a/src/bootstrap/defaults/config.codegen.toml
+++ b/src/bootstrap/defaults/config.codegen.toml
@@ -7,6 +7,8 @@ compiler-docs = true
 # This enables debug-assertions in LLVM,
 # catching logic errors in codegen much earlier in the process.
 assertions = true
+# enable warnings during the llvm compilation
+enable-warnings = true
 
 [rust]
 # This enables `RUSTC_LOG=debug`, avoiding confusing situations
diff --git a/src/bootstrap/defaults/config.user.toml b/src/bootstrap/defaults/config.user.toml
index 48ae2fe448d..ee271c3fb51 100644
--- a/src/bootstrap/defaults/config.user.toml
+++ b/src/bootstrap/defaults/config.user.toml
@@ -11,3 +11,7 @@ extended = true
 [llvm]
 # Most users installing from source want to build all parts of the project from source, not just rustc itself.
 download-ci-llvm = false
+
+[dist]
+# Use better compression when preparing tarballs.
+compression-profile = "balanced"
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index a3d9cb3e10c..dceb4bd1b89 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -210,6 +210,8 @@ fn make_win_dist(
         rustc_dlls.push("libgcc_s_seh-1.dll");
     }
 
+    // Libraries necessary to link the windows-gnu toolchains.
+    // System libraries will be preferred if they are available (see #67429).
     let target_libs = [
         //MinGW libs
         "libgcc.a",
@@ -223,6 +225,7 @@ fn make_win_dist(
         "libmoldname.a",
         "libpthread.a",
         //Windows import libs
+        //This should contain only the set of libraries necessary to link the standard library.
         "libadvapi32.a",
         "libbcrypt.a",
         "libcomctl32.a",
@@ -236,6 +239,7 @@ fn make_win_dist(
         "libkernel32.a",
         "libmsimg32.a",
         "libmsvcrt.a",
+        "libntdll.a",
         "libodbc32.a",
         "libole32.a",
         "liboleaut32.a",
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index ac3843c3344..42d895a3413 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -210,10 +210,13 @@ install!((self, builder, _config),
         }
     };
     LlvmTools, alias = "llvm-tools", Self::should_build(_config), only_hosts: true, {
-        let tarball = builder
-            .ensure(dist::LlvmTools { target: self.target })
-            .expect("missing llvm-tools");
-        install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball);
+        if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) {
+            install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball);
+        } else {
+            builder.info(
+                &format!("skipping llvm-tools stage{} ({}): external LLVM", self.compiler.stage, self.target),
+            );
+        }
     };
     Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, {
         if let Some(tarball) = builder.ensure(dist::Rustfmt {
diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs
index 5c0322e18a4..4fb00f65dc1 100644
--- a/src/bootstrap/job.rs
+++ b/src/bootstrap/job.rs
@@ -27,52 +27,54 @@
 //! Note that this module has a #[cfg(windows)] above it as none of this logic
 //! is required on Unix.
 
-#![allow(nonstandard_style, dead_code)]
-
 use crate::Build;
 use std::env;
+use std::ffi::c_void;
 use std::io;
 use std::mem;
-use std::ptr;
 
-use winapi::shared::minwindef::{DWORD, FALSE, LPVOID};
-use winapi::um::errhandlingapi::SetErrorMode;
-use winapi::um::handleapi::{CloseHandle, DuplicateHandle};
-use winapi::um::jobapi2::{AssignProcessToJobObject, CreateJobObjectW, SetInformationJobObject};
-use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcess};
-use winapi::um::winbase::{BELOW_NORMAL_PRIORITY_CLASS, SEM_NOGPFAULTERRORBOX};
-use winapi::um::winnt::{
-    JobObjectExtendedLimitInformation, DUPLICATE_SAME_ACCESS, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
-    JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
+use windows::{
+    core::PCWSTR,
+    Win32::Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE},
+    Win32::System::Diagnostics::Debug::{SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE},
+    Win32::System::JobObjects::{
+        AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation,
+        SetInformationJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
+        JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS,
+    },
+    Win32::System::Threading::{
+        GetCurrentProcess, OpenProcess, BELOW_NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
+    },
 };
 
 pub unsafe fn setup(build: &mut Build) {
     // Enable the Windows Error Reporting dialog which msys disables,
     // so we can JIT debug rustc
-    let mode = SetErrorMode(0);
+    let mode = SetErrorMode(THREAD_ERROR_MODE::default());
+    let mode = THREAD_ERROR_MODE(mode);
     SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX);
 
     // Create a new job object for us to use
-    let job = CreateJobObjectW(ptr::null_mut(), ptr::null());
-    assert!(!job.is_null(), "{}", io::Error::last_os_error());
+    let job = CreateJobObjectW(None, PCWSTR::null()).unwrap();
 
     // Indicate that when all handles to the job object are gone that all
     // process in the object should be killed. Note that this includes our
     // entire process tree by default because we've added ourselves and our
     // children will reside in the job by default.
-    let mut info = mem::zeroed::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>();
+    let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default();
     info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
     if build.config.low_priority {
         info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
-        info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
+        info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS.0;
     }
     let r = SetInformationJobObject(
         job,
         JobObjectExtendedLimitInformation,
-        &mut info as *mut _ as LPVOID,
-        mem::size_of_val(&info) as DWORD,
-    );
-    assert!(r != 0, "{}", io::Error::last_os_error());
+        &info as *const _ as *const c_void,
+        mem::size_of_val(&info) as u32,
+    )
+    .ok();
+    assert!(r.is_ok(), "{}", io::Error::last_os_error());
 
     // Assign our process to this job object. Note that if this fails, one very
     // likely reason is that we are ourselves already in a job object! This can
@@ -83,8 +85,8 @@ pub unsafe fn setup(build: &mut Build) {
     // Also note that nested jobs (why this might fail) are supported in recent
     // versions of Windows, but the version of Windows that our bots are running
     // at least don't support nested job objects.
-    let r = AssignProcessToJobObject(job, GetCurrentProcess());
-    if r == 0 {
+    let r = AssignProcessToJobObject(job, GetCurrentProcess()).ok();
+    if r.is_err() {
         CloseHandle(job);
         return;
     }
@@ -102,31 +104,32 @@ pub unsafe fn setup(build: &mut Build) {
         Err(..) => return,
     };
 
-    let parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid.parse().unwrap());
-
-    // If we get a null parent pointer here, it is possible that either
-    // we have got an invalid pid or the parent process has been closed.
-    // Since the first case rarely happens
-    // (only when wrongly setting the environmental variable),
-    // so it might be better to improve the experience of the second case
-    // when users have interrupted the parent process and we don't finish
-    // duplicating the handle yet.
-    // We just need close the job object if that occurs.
-    if parent.is_null() {
-        CloseHandle(job);
-        return;
-    }
+    let parent = match OpenProcess(PROCESS_DUP_HANDLE, false, pid.parse().unwrap()).ok() {
+        Some(parent) => parent,
+        _ => {
+            // If we get a null parent pointer here, it is possible that either
+            // we have an invalid pid or the parent process has been closed.
+            // Since the first case rarely happens
+            // (only when wrongly setting the environmental variable),
+            // it might be better to improve the experience of the second case
+            // when users have interrupted the parent process and we haven't finish
+            // duplicating the handle yet. We just need close the job object if that occurs.
+            CloseHandle(job);
+            return;
+        }
+    };
 
-    let mut parent_handle = ptr::null_mut();
+    let mut parent_handle = HANDLE::default();
     let r = DuplicateHandle(
         GetCurrentProcess(),
         job,
         parent,
         &mut parent_handle,
         0,
-        FALSE,
+        false,
         DUPLICATE_SAME_ACCESS,
-    );
+    )
+    .ok();
 
     // If this failed, well at least we tried! An example of DuplicateHandle
     // failing in the past has been when the wrong python2 package spawned this
@@ -134,7 +137,7 @@ pub unsafe fn setup(build: &mut Build) {
     // `mingw-w64-x86_64-python2`. Not sure why it failed, but the "failure
     // mode" here is that we only clean everything up when the build system
     // dies, not when the python parent does, so not too bad.
-    if r != 0 {
+    if r.is_err() {
         CloseHandle(job);
     }
 }
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index e4b4192cf08..54aa5a585bb 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -55,6 +55,7 @@ mod format;
 mod install;
 mod metadata;
 mod native;
+mod render_tests;
 mod run;
 mod sanity;
 mod setup;
@@ -88,6 +89,7 @@ pub use crate::builder::PathSet;
 use crate::cache::{Interned, INTERNER};
 pub use crate::config::Config;
 pub use crate::flags::Subcommand;
+use termcolor::{ColorChoice, StandardStream, WriteColor};
 
 const LLVM_TOOLS: &[&str] = &[
     "llvm-cov",      // used to generate coverage report
@@ -144,6 +146,9 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)]
     // FIXME: Used by filetime, but we should not be triggering on external dependencies.
     (Some(Mode::Rustc), "emulate_second_only_system", None),
     (Some(Mode::ToolRustc), "emulate_second_only_system", None),
+    // Needed to avoid the need to copy windows.lib into the sysroot.
+    (Some(Mode::Rustc), "windows_raw_dylib", None),
+    (Some(Mode::ToolRustc), "windows_raw_dylib", None),
 ];
 
 /// A structure representing a Rust compiler.
@@ -495,6 +500,7 @@ impl Build {
 
         // Make a symbolic link so we can use a consistent directory in the documentation.
         let build_triple = build.out.join(&build.build.triple);
+        t!(fs::create_dir_all(&build_triple));
         let host = build.out.join("host");
         if let Err(e) = symlink_dir(&build.config, &build_triple, &host) {
             if e.kind() != ErrorKind::AlreadyExists {
@@ -1579,6 +1585,31 @@ to download LLVM rather than building it.
 
         self.config.ninja_in_file
     }
+
+    pub fn colored_stdout<R, F: FnOnce(&mut dyn WriteColor) -> R>(&self, f: F) -> R {
+        self.colored_stream_inner(StandardStream::stdout, self.config.stdout_is_tty, f)
+    }
+
+    pub fn colored_stderr<R, F: FnOnce(&mut dyn WriteColor) -> R>(&self, f: F) -> R {
+        self.colored_stream_inner(StandardStream::stderr, self.config.stderr_is_tty, f)
+    }
+
+    fn colored_stream_inner<R, F, C>(&self, constructor: C, is_tty: bool, f: F) -> R
+    where
+        C: Fn(ColorChoice) -> StandardStream,
+        F: FnOnce(&mut dyn WriteColor) -> R,
+    {
+        let choice = match self.config.color {
+            flags::Color::Always => ColorChoice::Always,
+            flags::Color::Never => ColorChoice::Never,
+            flags::Color::Auto if !is_tty => ColorChoice::Never,
+            flags::Color::Auto => ColorChoice::Auto,
+        };
+        let mut stream = constructor(choice);
+        let result = f(&mut stream);
+        stream.reset().unwrap();
+        result
+    }
 }
 
 #[cfg(unix)]
diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs
index 2e62c950709..5f254761aa1 100644
--- a/src/bootstrap/metrics.rs
+++ b/src/bootstrap/metrics.rs
@@ -51,6 +51,7 @@ impl BuildMetrics {
             duration_excluding_children_sec: Duration::ZERO,
 
             children: Vec::new(),
+            tests: Vec::new(),
         });
     }
 
@@ -72,6 +73,16 @@ impl BuildMetrics {
         }
     }
 
+    pub(crate) fn record_test(&self, name: &str, outcome: TestOutcome) {
+        let mut state = self.state.borrow_mut();
+        state
+            .running_steps
+            .last_mut()
+            .unwrap()
+            .tests
+            .push(Test { name: name.to_string(), outcome });
+    }
+
     fn collect_stats(&self, state: &mut MetricsState) {
         let step = state.running_steps.last_mut().unwrap();
 
@@ -125,6 +136,14 @@ impl BuildMetrics {
     }
 
     fn prepare_json_step(&self, step: StepMetrics) -> JsonNode {
+        let mut children = Vec::new();
+        children.extend(step.children.into_iter().map(|child| self.prepare_json_step(child)));
+        children.extend(
+            step.tests
+                .into_iter()
+                .map(|test| JsonNode::Test { name: test.name, outcome: test.outcome }),
+        );
+
         JsonNode::RustbuildStep {
             type_: step.type_,
             debug_repr: step.debug_repr,
@@ -135,11 +154,7 @@ impl BuildMetrics {
                     / step.duration_excluding_children_sec.as_secs_f64(),
             },
 
-            children: step
-                .children
-                .into_iter()
-                .map(|child| self.prepare_json_step(child))
-                .collect(),
+            children,
         }
     }
 }
@@ -161,6 +176,12 @@ struct StepMetrics {
     duration_excluding_children_sec: Duration,
 
     children: Vec<StepMetrics>,
+    tests: Vec<Test>,
+}
+
+struct Test {
+    name: String,
+    outcome: TestOutcome,
 }
 
 #[derive(Serialize, Deserialize)]
@@ -190,6 +211,19 @@ enum JsonNode {
 
         children: Vec<JsonNode>,
     },
+    Test {
+        name: String,
+        #[serde(flatten)]
+        outcome: TestOutcome,
+    },
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(tag = "outcome", rename_all = "snake_case")]
+pub(crate) enum TestOutcome {
+    Passed,
+    Failed,
+    Ignored { ignore_reason: Option<String> },
 }
 
 #[derive(Serialize, Deserialize)]
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 040e36ea5f8..dff46b500e3 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -304,6 +304,7 @@ impl Step for Llvm {
         let assertions = if builder.config.llvm_assertions { "ON" } else { "OFF" };
         let plugins = if builder.config.llvm_plugins { "ON" } else { "OFF" };
         let enable_tests = if builder.config.llvm_tests { "ON" } else { "OFF" };
+        let enable_warnings = if builder.config.llvm_enable_warnings { "ON" } else { "OFF" };
 
         cfg.out_dir(&out_dir)
             .profile(profile)
@@ -321,7 +322,8 @@ impl Step for Llvm {
             .define("LLVM_ENABLE_Z3_SOLVER", "OFF")
             .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string())
             .define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap())
-            .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native);
+            .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native)
+            .define("LLVM_ENABLE_WARNINGS", enable_warnings);
 
         // Parts of our test suite rely on the `FileCheck` tool, which is built by default in
         // `build/$TARGET/llvm/build/bin` is but *not* then installed to `build/$TARGET/llvm/bin`.
@@ -483,11 +485,6 @@ impl Step for Llvm {
             cfg.define(key, val);
         }
 
-        // FIXME: we don't actually need to build all LLVM tools and all LLVM
-        //        libraries here, e.g., we just want a few components and a few
-        //        tools. Figure out how to filter them down and only build the right
-        //        tools and libs on all platforms.
-
         if builder.config.dry_run() {
             return res;
         }
@@ -570,6 +567,8 @@ fn configure_cmake(
             cfg.define("CMAKE_SYSTEM_NAME", "Haiku");
         } else if target.contains("solaris") || target.contains("illumos") {
             cfg.define("CMAKE_SYSTEM_NAME", "SunOS");
+        } else if target.contains("linux") {
+            cfg.define("CMAKE_SYSTEM_NAME", "Linux");
         }
         // When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in
         // that case like CMake we cannot easily determine system version either.
diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs
new file mode 100644
index 00000000000..af2370d439e
--- /dev/null
+++ b/src/bootstrap/render_tests.rs
@@ -0,0 +1,376 @@
+//! This module renders the JSON output of libtest into a human-readable form, trying to be as
+//! similar to libtest's native output as possible.
+//!
+//! This is needed because we need to use libtest in JSON mode to extract granluar information
+//! about the executed tests. Doing so suppresses the human-readable output, and (compared to Cargo
+//! and rustc) libtest doesn't include the rendered human-readable output as a JSON field. We had
+//! to reimplement all the rendering logic in this module because of that.
+
+use crate::builder::Builder;
+use std::io::{BufRead, BufReader, Write};
+use std::process::{ChildStdout, Command, Stdio};
+use std::time::Duration;
+use termcolor::{Color, ColorSpec, WriteColor};
+
+const TERSE_TESTS_PER_LINE: usize = 88;
+
+pub(crate) fn add_flags_and_try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool {
+    if cmd.get_args().position(|arg| arg == "--").is_none() {
+        cmd.arg("--");
+    }
+    cmd.args(&["-Z", "unstable-options", "--format", "json"]);
+
+    try_run_tests(builder, cmd)
+}
+
+pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool {
+    if builder.config.dry_run() {
+        return true;
+    }
+
+    if !run_tests(builder, cmd) {
+        if builder.fail_fast {
+            crate::detail_exit(1);
+        } else {
+            let mut failures = builder.delayed_failures.borrow_mut();
+            failures.push(format!("{cmd:?}"));
+            false
+        }
+    } else {
+        true
+    }
+}
+
+fn run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool {
+    cmd.stdout(Stdio::piped());
+
+    builder.verbose(&format!("running: {cmd:?}"));
+
+    let mut process = cmd.spawn().unwrap();
+
+    // This runs until the stdout of the child is closed, which means the child exited. We don't
+    // run this on another thread since the builder is not Sync.
+    Renderer::new(process.stdout.take().unwrap(), builder).render_all();
+
+    let result = process.wait_with_output().unwrap();
+    if !result.status.success() && builder.is_verbose() {
+        println!(
+            "\n\ncommand did not execute successfully: {cmd:?}\n\
+             expected success, got: {}",
+            result.status
+        );
+    }
+
+    result.status.success()
+}
+
+struct Renderer<'a> {
+    stdout: BufReader<ChildStdout>,
+    failures: Vec<TestOutcome>,
+    benches: Vec<BenchOutcome>,
+    builder: &'a Builder<'a>,
+    tests_count: Option<usize>,
+    executed_tests: usize,
+    terse_tests_in_line: usize,
+}
+
+impl<'a> Renderer<'a> {
+    fn new(stdout: ChildStdout, builder: &'a Builder<'a>) -> Self {
+        Self {
+            stdout: BufReader::new(stdout),
+            benches: Vec::new(),
+            failures: Vec::new(),
+            builder,
+            tests_count: None,
+            executed_tests: 0,
+            terse_tests_in_line: 0,
+        }
+    }
+
+    fn render_all(mut self) {
+        let mut line = String::new();
+        loop {
+            line.clear();
+            match self.stdout.read_line(&mut line) {
+                Ok(_) => {}
+                Err(err) if err.kind() == std::io::ErrorKind::UnexpectedEof => break,
+                Err(err) => panic!("failed to read output of test runner: {err}"),
+            }
+            if line.is_empty() {
+                break;
+            }
+
+            let trimmed = line.trim();
+            if trimmed.starts_with("{") && trimmed.ends_with("}") {
+                self.render_message(match serde_json::from_str(&trimmed) {
+                    Ok(parsed) => parsed,
+                    Err(err) => {
+                        panic!("failed to parse libtest json output; error: {err}, line: {line:?}");
+                    }
+                });
+            } else {
+                // Handle non-JSON output, for example when --nocapture is passed.
+                print!("{line}");
+                let _ = std::io::stdout().flush();
+            }
+        }
+    }
+
+    fn render_test_outcome(&mut self, outcome: Outcome<'_>, test: &TestOutcome) {
+        self.executed_tests += 1;
+
+        #[cfg(feature = "build-metrics")]
+        self.builder.metrics.record_test(
+            &test.name,
+            match outcome {
+                Outcome::Ok | Outcome::BenchOk => crate::metrics::TestOutcome::Passed,
+                Outcome::Failed => crate::metrics::TestOutcome::Failed,
+                Outcome::Ignored { reason } => crate::metrics::TestOutcome::Ignored {
+                    ignore_reason: reason.map(|s| s.to_string()),
+                },
+            },
+        );
+
+        if self.builder.config.verbose_tests {
+            self.render_test_outcome_verbose(outcome, test);
+        } else {
+            self.render_test_outcome_terse(outcome, test);
+        }
+    }
+
+    fn render_test_outcome_verbose(&self, outcome: Outcome<'_>, test: &TestOutcome) {
+        print!("test {} ... ", test.name);
+        self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap();
+        if let Some(exec_time) = test.exec_time {
+            print!(" ({exec_time:.2?})");
+        }
+        println!();
+    }
+
+    fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, _: &TestOutcome) {
+        if self.terse_tests_in_line != 0 && self.terse_tests_in_line % TERSE_TESTS_PER_LINE == 0 {
+            if let Some(total) = self.tests_count {
+                let total = total.to_string();
+                let executed = format!("{:>width$}", self.executed_tests - 1, width = total.len());
+                print!(" {executed}/{total}");
+            }
+            println!();
+            self.terse_tests_in_line = 0;
+        }
+
+        self.terse_tests_in_line += 1;
+        self.builder.colored_stdout(|stdout| outcome.write_short(stdout)).unwrap();
+        let _ = std::io::stdout().flush();
+    }
+
+    fn render_suite_outcome(&self, outcome: Outcome<'_>, suite: &SuiteOutcome) {
+        // The terse output doesn't end with a newline, so we need to add it ourselves.
+        if !self.builder.config.verbose_tests {
+            println!();
+        }
+
+        if !self.failures.is_empty() {
+            println!("\nfailures:\n");
+            for failure in &self.failures {
+                if let Some(stdout) = &failure.stdout {
+                    println!("---- {} stdout ----", failure.name);
+                    println!("{stdout}");
+                }
+            }
+
+            println!("\nfailures:");
+            for failure in &self.failures {
+                println!("    {}", failure.name);
+            }
+        }
+
+        if !self.benches.is_empty() {
+            println!("\nbenchmarks:");
+
+            let mut rows = Vec::new();
+            for bench in &self.benches {
+                rows.push((
+                    &bench.name,
+                    format!("{:.2?}/iter", Duration::from_nanos(bench.median)),
+                    format!("+/- {:.2?}", Duration::from_nanos(bench.deviation)),
+                ));
+            }
+
+            let max_0 = rows.iter().map(|r| r.0.len()).max().unwrap_or(0);
+            let max_1 = rows.iter().map(|r| r.1.len()).max().unwrap_or(0);
+            let max_2 = rows.iter().map(|r| r.2.len()).max().unwrap_or(0);
+            for row in &rows {
+                println!("    {:<max_0$} {:>max_1$} {:>max_2$}", row.0, row.1, row.2);
+            }
+        }
+
+        print!("\ntest result: ");
+        self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap();
+        println!(
+            ". {} passed; {} failed; {} ignored; {} measured; {} filtered out; \
+             finished in {:.2?}\n",
+            suite.passed,
+            suite.failed,
+            suite.ignored,
+            suite.measured,
+            suite.filtered_out,
+            Duration::from_secs_f64(suite.exec_time)
+        );
+    }
+
+    fn render_message(&mut self, message: Message) {
+        match message {
+            Message::Suite(SuiteMessage::Started { test_count }) => {
+                println!("\nrunning {test_count} tests");
+                self.executed_tests = 0;
+                self.terse_tests_in_line = 0;
+                self.tests_count = Some(test_count);
+            }
+            Message::Suite(SuiteMessage::Ok(outcome)) => {
+                self.render_suite_outcome(Outcome::Ok, &outcome);
+            }
+            Message::Suite(SuiteMessage::Failed(outcome)) => {
+                self.render_suite_outcome(Outcome::Failed, &outcome);
+            }
+            Message::Bench(outcome) => {
+                // The formatting for benchmarks doesn't replicate 1:1 the formatting libtest
+                // outputs, mostly because libtest's formatting is broken in terse mode, which is
+                // the default used by our monorepo. We use a different formatting instead:
+                // successful benchmarks are just showed as "benchmarked"/"b", and the details are
+                // outputted at the bottom like failures.
+                let fake_test_outcome = TestOutcome {
+                    name: outcome.name.clone(),
+                    exec_time: None,
+                    stdout: None,
+                    message: None,
+                };
+                self.render_test_outcome(Outcome::BenchOk, &fake_test_outcome);
+                self.benches.push(outcome);
+            }
+            Message::Test(TestMessage::Ok(outcome)) => {
+                self.render_test_outcome(Outcome::Ok, &outcome);
+            }
+            Message::Test(TestMessage::Ignored(outcome)) => {
+                self.render_test_outcome(
+                    Outcome::Ignored { reason: outcome.message.as_deref() },
+                    &outcome,
+                );
+            }
+            Message::Test(TestMessage::Failed(outcome)) => {
+                self.render_test_outcome(Outcome::Failed, &outcome);
+                self.failures.push(outcome);
+            }
+            Message::Test(TestMessage::Timeout { name }) => {
+                println!("test {name} has been running for a long time");
+            }
+            Message::Test(TestMessage::Started) => {} // Not useful
+        }
+    }
+}
+
+enum Outcome<'a> {
+    Ok,
+    BenchOk,
+    Failed,
+    Ignored { reason: Option<&'a str> },
+}
+
+impl Outcome<'_> {
+    fn write_short(&self, writer: &mut dyn WriteColor) -> Result<(), std::io::Error> {
+        match self {
+            Outcome::Ok => {
+                writer.set_color(&ColorSpec::new().set_fg(Some(Color::Green)))?;
+                write!(writer, ".")?;
+            }
+            Outcome::BenchOk => {
+                writer.set_color(&ColorSpec::new().set_fg(Some(Color::Cyan)))?;
+                write!(writer, "b")?;
+            }
+            Outcome::Failed => {
+                writer.set_color(&ColorSpec::new().set_fg(Some(Color::Red)))?;
+                write!(writer, "F")?;
+            }
+            Outcome::Ignored { .. } => {
+                writer.set_color(&ColorSpec::new().set_fg(Some(Color::Yellow)))?;
+                write!(writer, "i")?;
+            }
+        }
+        writer.reset()
+    }
+
+    fn write_long(&self, writer: &mut dyn WriteColor) -> Result<(), std::io::Error> {
+        match self {
+            Outcome::Ok => {
+                writer.set_color(&ColorSpec::new().set_fg(Some(Color::Green)))?;
+                write!(writer, "ok")?;
+            }
+            Outcome::BenchOk => {
+                writer.set_color(&ColorSpec::new().set_fg(Some(Color::Cyan)))?;
+                write!(writer, "benchmarked")?;
+            }
+            Outcome::Failed => {
+                writer.set_color(&ColorSpec::new().set_fg(Some(Color::Red)))?;
+                write!(writer, "FAILED")?;
+            }
+            Outcome::Ignored { reason } => {
+                writer.set_color(&ColorSpec::new().set_fg(Some(Color::Yellow)))?;
+                write!(writer, "ignored")?;
+                if let Some(reason) = reason {
+                    write!(writer, ", {reason}")?;
+                }
+            }
+        }
+        writer.reset()
+    }
+}
+
+#[derive(serde_derive::Deserialize)]
+#[serde(tag = "type", rename_all = "snake_case")]
+enum Message {
+    Suite(SuiteMessage),
+    Test(TestMessage),
+    Bench(BenchOutcome),
+}
+
+#[derive(serde_derive::Deserialize)]
+#[serde(tag = "event", rename_all = "snake_case")]
+enum SuiteMessage {
+    Ok(SuiteOutcome),
+    Failed(SuiteOutcome),
+    Started { test_count: usize },
+}
+
+#[derive(serde_derive::Deserialize)]
+struct SuiteOutcome {
+    passed: usize,
+    failed: usize,
+    ignored: usize,
+    measured: usize,
+    filtered_out: usize,
+    exec_time: f64,
+}
+
+#[derive(serde_derive::Deserialize)]
+#[serde(tag = "event", rename_all = "snake_case")]
+enum TestMessage {
+    Ok(TestOutcome),
+    Failed(TestOutcome),
+    Ignored(TestOutcome),
+    Timeout { name: String },
+    Started,
+}
+
+#[derive(serde_derive::Deserialize)]
+struct BenchOutcome {
+    name: String,
+    median: u64,
+    deviation: u64,
+}
+
+#[derive(serde_derive::Deserialize)]
+struct TestOutcome {
+    name: String,
+    exec_time: Option<f64>,
+    stdout: Option<String>,
+    message: Option<String>,
+}
diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs
index fc850a22b2f..7fa8a4d9d7f 100644
--- a/src/bootstrap/tarball.rs
+++ b/src/bootstrap/tarball.rs
@@ -318,6 +318,7 @@ impl<'a> Tarball<'a> {
             assert!(!formats.is_empty(), "dist.compression-formats can't be empty");
             cmd.arg("--compression-formats").arg(formats.join(","));
         }
+        cmd.args(&["--compression-profile", &self.builder.config.dist_compression_profile]);
         self.builder.run(&mut cmd);
 
         // Ensure there are no symbolic links in the tarball. In particular,
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index f5d680df113..29d37c09d88 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -20,6 +20,7 @@ use crate::dist;
 use crate::doc::DocumentationFormat;
 use crate::flags::Subcommand;
 use crate::native;
+use crate::render_tests::add_flags_and_try_run_tests;
 use crate::tool::{self, SourceType, Tool};
 use crate::toolstate::ToolState;
 use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t};
@@ -123,7 +124,7 @@ impl Step for CrateJsonDocLint {
             SourceType::InTree,
             &[],
         );
-        try_run(builder, &mut cargo.into());
+        add_flags_and_try_run_tests(builder, &mut cargo.into());
     }
 }
 
@@ -172,7 +173,7 @@ You can skip linkcheck with --exclude src/tools/linkchecker"
             SourceType::InTree,
             &[],
         );
-        try_run(builder, &mut cargo.into());
+        add_flags_and_try_run_tests(builder, &mut cargo.into());
 
         // Build all the default documentation.
         builder.default_doc(&[]);
@@ -333,7 +334,7 @@ impl Step for Cargo {
 
         cargo.env("PATH", &path_for_cargo(builder, compiler));
 
-        try_run(builder, &mut cargo.into());
+        add_flags_and_try_run_tests(builder, &mut cargo.into());
     }
 }
 
@@ -392,7 +393,7 @@ impl Step for RustAnalyzer {
         cargo.add_rustc_lib_path(builder, compiler);
         cargo.arg("--").args(builder.config.cmd.test_args());
 
-        builder.run(&mut cargo.into());
+        add_flags_and_try_run_tests(builder, &mut cargo.into());
     }
 }
 
@@ -445,7 +446,7 @@ impl Step for Rustfmt {
 
         cargo.add_rustc_lib_path(builder, compiler);
 
-        builder.run(&mut cargo.into());
+        add_flags_and_try_run_tests(builder, &mut cargo.into());
     }
 }
 
@@ -496,7 +497,7 @@ impl Step for RustDemangler {
 
         cargo.add_rustc_lib_path(builder, compiler);
 
-        builder.run(&mut cargo.into());
+        add_flags_and_try_run_tests(builder, &mut cargo.into());
     }
 }
 
@@ -637,8 +638,7 @@ impl Step for Miri {
         // Forward test filters.
         cargo.arg("--").args(builder.config.cmd.test_args());
 
-        let mut cargo = Command::from(cargo);
-        builder.run(&mut cargo);
+        add_flags_and_try_run_tests(builder, &mut cargo.into());
 
         // # Run `cargo miri test`.
         // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures
@@ -711,7 +711,7 @@ impl Step for CompiletestTest {
         );
         cargo.allow_features("test");
 
-        try_run(builder, &mut cargo.into());
+        add_flags_and_try_run_tests(builder, &mut cargo.into());
     }
 }
 
@@ -1118,7 +1118,11 @@ impl Step for Tidy {
         cmd.arg(&builder.src);
         cmd.arg(&builder.initial_cargo);
         cmd.arg(&builder.out);
-        cmd.arg(builder.jobs().to_string());
+        // Tidy is heavily IO constrained. Still respect `-j`, but use a higher limit if `jobs` hasn't been configured.
+        let jobs = builder.config.jobs.unwrap_or_else(|| {
+            8 * std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32
+        });
+        cmd.arg(jobs.to_string());
         if builder.is_verbose() {
             cmd.arg("--verbose");
         }
@@ -1189,7 +1193,7 @@ impl Step for TidySelfTest {
             SourceType::InTree,
             &[],
         );
-        try_run(builder, &mut cargo.into());
+        add_flags_and_try_run_tests(builder, &mut cargo.into());
     }
 }
 
@@ -1616,9 +1620,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             cmd.arg("--verbose");
         }
 
-        if !builder.config.verbose_tests {
-            cmd.arg("--quiet");
-        }
+        cmd.arg("--json");
 
         let mut llvm_components_passed = false;
         let mut copts_passed = false;
@@ -1769,7 +1771,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             suite, mode, &compiler.host, target
         ));
         let _time = util::timeit(&builder);
-        try_run(builder, &mut cmd);
+        crate::render_tests::try_run_tests(builder, &mut cmd);
 
         if let Some(compare_mode) = compare_mode {
             cmd.arg("--compare-mode").arg(compare_mode);
@@ -1778,7 +1780,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
                 suite, mode, compare_mode, &compiler.host, target
             ));
             let _time = util::timeit(&builder);
-            try_run(builder, &mut cmd);
+            crate::render_tests::try_run_tests(builder, &mut cmd);
         }
     }
 }
@@ -2180,9 +2182,8 @@ impl Step for Crate {
         cargo.arg("--");
         cargo.args(&builder.config.cmd.test_args());
 
-        if !builder.config.verbose_tests {
-            cargo.arg("--quiet");
-        }
+        cargo.arg("-Z").arg("unstable-options");
+        cargo.arg("--format").arg("json");
 
         if target.contains("emscripten") {
             cargo.env(
@@ -2210,7 +2211,7 @@ impl Step for Crate {
             target
         ));
         let _time = util::timeit(&builder);
-        try_run(builder, &mut cargo.into());
+        crate::render_tests::try_run_tests(builder, &mut cargo.into());
     }
 }
 
@@ -2330,7 +2331,7 @@ impl Step for CrateRustdoc {
         ));
         let _time = util::timeit(&builder);
 
-        try_run(builder, &mut cargo.into());
+        add_flags_and_try_run_tests(builder, &mut cargo.into());
     }
 }
 
@@ -2391,17 +2392,13 @@ impl Step for CrateRustdocJsonTypes {
             cargo.arg("'-Ctarget-feature=-crt-static'");
         }
 
-        if !builder.config.verbose_tests {
-            cargo.arg("--quiet");
-        }
-
         builder.info(&format!(
             "{} rustdoc-json-types stage{} ({} -> {})",
             test_kind, compiler.stage, &compiler.host, target
         ));
         let _time = util::timeit(&builder);
 
-        try_run(builder, &mut cargo.into());
+        add_flags_and_try_run_tests(builder, &mut cargo.into());
     }
 }
 
@@ -2570,7 +2567,7 @@ impl Step for Bootstrap {
         // rustbuild tests are racy on directory creation so just run them one at a time.
         // Since there's not many this shouldn't be a problem.
         cmd.arg("--test-threads=1");
-        try_run(builder, &mut cmd);
+        add_flags_and_try_run_tests(builder, &mut cmd);
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -2651,7 +2648,7 @@ impl Step for ReplacePlaceholderTest {
             SourceType::InTree,
             &[],
         );
-        try_run(builder, &mut cargo.into());
+        add_flags_and_try_run_tests(builder, &mut cargo.into());
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 93e53d383cd..9a6aaffe22b 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -155,29 +155,30 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
     fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> {
         use std::ffi::OsStr;
         use std::os::windows::ffi::OsStrExt;
-        use std::ptr;
-
-        use winapi::shared::minwindef::{DWORD, WORD};
-        use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING};
-        use winapi::um::handleapi::CloseHandle;
-        use winapi::um::ioapiset::DeviceIoControl;
-        use winapi::um::winbase::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT};
-        use winapi::um::winioctl::FSCTL_SET_REPARSE_POINT;
-        use winapi::um::winnt::{
-            FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_WRITE,
-            IO_REPARSE_TAG_MOUNT_POINT, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, WCHAR,
+
+        use windows::{
+            core::PCWSTR,
+            Win32::Foundation::{CloseHandle, HANDLE},
+            Win32::Storage::FileSystem::{
+                CreateFileW, FILE_ACCESS_FLAGS, FILE_FLAG_BACKUP_SEMANTICS,
+                FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE,
+                MAXIMUM_REPARSE_DATA_BUFFER_SIZE, OPEN_EXISTING,
+            },
+            Win32::System::Ioctl::FSCTL_SET_REPARSE_POINT,
+            Win32::System::SystemServices::{GENERIC_WRITE, IO_REPARSE_TAG_MOUNT_POINT},
+            Win32::System::IO::DeviceIoControl,
         };
 
         #[allow(non_snake_case)]
         #[repr(C)]
         struct REPARSE_MOUNTPOINT_DATA_BUFFER {
-            ReparseTag: DWORD,
-            ReparseDataLength: DWORD,
-            Reserved: WORD,
-            ReparseTargetLength: WORD,
-            ReparseTargetMaximumLength: WORD,
-            Reserved1: WORD,
-            ReparseTarget: WCHAR,
+            ReparseTag: u32,
+            ReparseDataLength: u32,
+            Reserved: u16,
+            ReparseTargetLength: u16,
+            ReparseTargetMaximumLength: u16,
+            Reserved1: u16,
+            ReparseTarget: u16,
         }
 
         fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
@@ -193,17 +194,20 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
 
         let path = to_u16s(junction)?;
 
-        unsafe {
-            let h = CreateFileW(
-                path.as_ptr(),
-                GENERIC_WRITE,
+        let h = unsafe {
+            CreateFileW(
+                PCWSTR(path.as_ptr()),
+                FILE_ACCESS_FLAGS(GENERIC_WRITE),
                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                ptr::null_mut(),
+                None,
                 OPEN_EXISTING,
                 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
-                ptr::null_mut(),
-            );
+                HANDLE::default(),
+            )
+        }
+        .map_err(|_| io::Error::last_os_error())?;
 
+        unsafe {
             #[repr(C, align(8))]
             struct Align8<T>(T);
             let mut data = Align8([0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]);
@@ -219,27 +223,29 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
             }
             *buf.offset(i) = 0;
             i += 1;
+
             (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
-            (*db).ReparseTargetMaximumLength = (i * 2) as WORD;
-            (*db).ReparseTargetLength = ((i - 1) * 2) as WORD;
-            (*db).ReparseDataLength = (*db).ReparseTargetLength as DWORD + 12;
+            (*db).ReparseTargetMaximumLength = (i * 2) as u16;
+            (*db).ReparseTargetLength = ((i - 1) * 2) as u16;
+            (*db).ReparseDataLength = ((*db).ReparseTargetLength + 12) as u32;
 
-            let mut ret = 0;
-            let res = DeviceIoControl(
-                h as *mut _,
+            let mut ret = 0u32;
+            DeviceIoControl(
+                h,
                 FSCTL_SET_REPARSE_POINT,
-                db.cast(),
+                Some(db.cast()),
                 (*db).ReparseDataLength + 8,
-                ptr::null_mut(),
+                None,
                 0,
-                &mut ret,
-                ptr::null_mut(),
-            );
-
-            let out = if res == 0 { Err(io::Error::last_os_error()) } else { Ok(()) };
-            CloseHandle(h);
-            out
+                Some(&mut ret),
+                None,
+            )
+            .ok()
+            .map_err(|_| io::Error::last_os_error())?;
         }
+
+        unsafe { CloseHandle(h) };
+        Ok(())
     }
 }
 
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile
index 4e46bdee5ac..2089bf38716 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile
@@ -9,10 +9,10 @@ RUN bash /tmp/cross-apt-packages.sh
 # Required for cross-build gcc
 RUN apt-get update && \
     apt-get install -y --no-install-recommends \
-      libgmp-dev \
-      libmpfr-dev \
-      libmpc-dev \
-      && rm -rf /var/lib/apt/lists/*
+    libgmp-dev \
+    libmpfr-dev \
+    libmpc-dev \
+    && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/illumos-toolchain.sh /tmp/
 
@@ -28,6 +28,7 @@ RUN /scripts/cmake.sh
 
 ENV \
     AR_x86_64_unknown_illumos=x86_64-illumos-ar \
+    RANLIB_x86_64_unknown_illumos=x86_64-illumos-ranlib \
     CC_x86_64_unknown_illumos=x86_64-illumos-gcc \
     CXX_x86_64_unknown_illumos=x86_64-illumos-g++
 
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index 5feba4e0605..04fdb15f5ac 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -54,8 +54,8 @@ COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/
 RUN ./build-clang.sh
 ENV CC=clang CXX=clang++
 
-# rustc-perf version from 2022-07-22
-ENV PERF_COMMIT 3c253134664fdcba862c539d37f0de18557a9a4c
+# rustc-perf version from 2023-03-15
+ENV PERF_COMMIT 9dfaa35193154b690922347ee1141a06ec87a199
 RUN curl -LS -o perf.zip https://github.com/rust-lang/rustc-perf/archive/$PERF_COMMIT.zip && \
     unzip perf.zip && \
     mv rustc-perf-$PERF_COMMIT rustc-perf && \
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
index 9abfd4e9731..de0fb95efd0 100755
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
@@ -4,7 +4,7 @@ set -ex
 
 source shared.sh
 
-LLVM=llvmorg-15.0.0
+LLVM=llvmorg-16.0.0-rc4
 
 mkdir llvm-project
 cd llvm-project
diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
index 889a586b351..b5715024a84 100644
--- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
@@ -1,6 +1,8 @@
 FROM ubuntu:22.04
 
 ARG DEBIAN_FRONTEND=noninteractive
+# NOTE: intentionally uses python2 for x.py so we can test it still works.
+# validate-toolstate only runs in our CI, so it's ok for it to only support python3.
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
   make \
@@ -8,6 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   file \
   curl \
   ca-certificates \
+  python2.7 \
   python3 \
   python3-pip \
   python3-pkg-resources \
@@ -30,4 +33,4 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require
 COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
 COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
 
-ENV SCRIPT python3 ../x.py test --stage 0 src/tools/tidy tidyselftest
+ENV SCRIPT python2.7 ../x.py test --stage 0 src/tools/tidy tidyselftest
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile
index a007bf183ee..dc8a4aac768 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile
@@ -2,7 +2,6 @@ FROM ubuntu:22.04
 
 ARG DEBIAN_FRONTEND=noninteractive
 
-# NOTE: intentionally installs both python2 and python3 so we can test support for both.
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
   gcc-multilib \
@@ -11,8 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   file \
   curl \
   ca-certificates \
-  python2.7 \
-  python3 \
+  python3.11 \
   git \
   cmake \
   sudo \
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index b490b766663..c594288dcf8 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -74,7 +74,7 @@ x--expand-yaml-anchors--remove:
     env: {}
 
   - &job-linux-xl
-    os: ubuntu-20.04-xl
+    os: ubuntu-20.04-16core-64gb
     <<: *base-job
 
   - &job-macos-xl
@@ -82,7 +82,7 @@ x--expand-yaml-anchors--remove:
     <<: *base-job
 
   - &job-windows-xl
-    os: windows-latest-xl
+    os: windows-2019-8core-32gb
     <<: *base-job
 
   - &job-aarch64-linux
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 93dccb54c4e..fc4ed57fb82 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -58,6 +58,15 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules"
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps"
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-native-static"
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-units-std=1"
+RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set dist.compression-profile=best"
+
+# When building for mingw, limit the number of parallel linker jobs during
+# the LLVM build, as not to run out of memory.
+# This is an attempt to fix the spurious build error tracked by
+# https://github.com/rust-lang/rust/issues/108227.
+if isWindows && [[ ${CUSTOM_MINGW-0} -eq 1 ]]; then
+    RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.link-jobs=4"
+fi
 
 # Only produce xz tarballs on CI. gz tarballs will be generated by the release
 # process by recompressing the existing xz ones. This decreases the storage
diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py
index fe3083dc31e..d4d80e8f77c 100644
--- a/src/ci/stage-build.py
+++ b/src/ci/stage-build.py
@@ -175,8 +175,8 @@ class WindowsPipeline(Pipeline):
         return super().rustc_stage_2().with_suffix(".exe")
 
     def build_rustc_perf(self):
-        # rustc-perf version from 2022-07-22
-        perf_commit = "3c253134664fdcba862c539d37f0de18557a9a4c"
+        # rustc-perf version from 2023-03-15
+        perf_commit = "9dfaa35193154b690922347ee1141a06ec87a199"
         rustc_perf_zip_path = self.opt_artifacts() / "perf.zip"
 
         def download_rustc_perf():
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 9eafa27e2b7..2d74a224096 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -295,6 +295,7 @@ target | std | host | notes
 [`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? |  | RISC-V Xous (RV32IMAC ISA)
 `riscv32imc-esp-espidf` | ✓ |  | RISC-V ESP-IDF
 `riscv64gc-unknown-freebsd` |   |   | RISC-V FreeBSD
+`riscv64gc-unknown-fuchsia` |   |   | RISC-V Fuchsia
 `riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.0)
 [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
 `s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 3.2, MUSL)
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index 262cef3454a..f71aceff455 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -213,7 +213,7 @@ See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details.
 
 ## Example
 
-```text
+```rust,ignore
 #![feature(naked_functions)]
 
 use std::arch::asm;
@@ -238,7 +238,7 @@ pub extern "C" fn add_two(x: i32) {
              nop
              nop
              nop
-             lea rax, [rdi+2]
+             lea eax, [edi+2]
              ret
         ",
             options(noreturn)
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 6ca6edfd3c9..29912b95703 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -20,15 +20,13 @@ smallvec = "1.8.1"
 tempfile = "3"
 tracing = "0.1"
 tracing-tree = "0.2.0"
+threadpool = "1.8.1"
 
 [dependencies.tracing-subscriber]
 version = "0.3.3"
 default-features = false
 features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"]
 
-[target.'cfg(windows)'.dependencies]
-rayon = "1.5.1"
-
 [dev-dependencies]
 expect-test = "1.4.0"
 
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index bcdbbcacc4b..3a3bf6a7ab9 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -1,6 +1,6 @@
 use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_hir as hir;
-use rustc_infer::infer::{InferOk, TyCtxtInferExt};
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
 use rustc_infer::traits;
 use rustc_middle::ty::ToPredicate;
 use rustc_span::DUMMY_SP;
@@ -47,8 +47,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
 
                 // Require the type the impl is implemented on to match
                 // our type, and ignore the impl if there was a mismatch.
-                let cause = traits::ObligationCause::dummy();
-                let Ok(eq_result) = infcx.at(&cause, param_env).eq(impl_trait_ref.self_ty(), impl_ty) else {
+                let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, impl_trait_ref.self_ty(), impl_ty) else {
                         continue
                     };
                 let InferOk { value: (), obligations } = eq_result;
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 29c3afe0d95..e3e5454ef54 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -39,6 +39,7 @@ use std::hash::Hash;
 use std::mem;
 use thin_vec::ThinVec;
 
+use crate::clean::inline::merge_attrs;
 use crate::core::{self, DocContext, ImplTraitParam};
 use crate::formats::item_type::ItemType;
 use crate::visit_ast::Module as DocModule;
@@ -426,7 +427,7 @@ fn clean_projection<'tcx>(
     cx: &mut DocContext<'tcx>,
     def_id: Option<DefId>,
 ) -> Type {
-    if cx.tcx.def_kind(ty.skip_binder().def_id) == DefKind::ImplTraitPlaceholder {
+    if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) {
         let bounds = cx
             .tcx
             .explicit_item_bounds(ty.skip_binder().def_id)
@@ -2373,21 +2374,22 @@ fn clean_maybe_renamed_item<'tcx>(
             _ => unreachable!("not yet converted"),
         };
 
-        let mut extra_attrs = Vec::new();
+        let mut import_attrs = Vec::new();
+        let mut target_attrs = Vec::new();
         if let Some(import_id) = import_id &&
             let Some(hir::Node::Item(use_node)) = cx.tcx.hir().find_by_def_id(import_id)
         {
             let is_inline = inline::load_attrs(cx, import_id.to_def_id()).lists(sym::doc).get_word_attr(sym::inline).is_some();
             // Then we get all the various imports' attributes.
-            get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs, is_inline);
-            add_without_unwanted_attributes(&mut extra_attrs, inline::load_attrs(cx, def_id), is_inline);
+            get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut import_attrs, is_inline);
+            add_without_unwanted_attributes(&mut target_attrs, inline::load_attrs(cx, def_id), is_inline);
         } else {
             // We only keep the item's attributes.
-            extra_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
+            target_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
         }
 
-        let attrs = Attributes::from_ast(&extra_attrs);
-        let cfg = extra_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
+        let import_parent = import_id.map(|import_id| cx.tcx.local_parent(import_id).to_def_id());
+        let (attrs, cfg) =  merge_attrs(cx, import_parent, &target_attrs, Some(&import_attrs));
 
         let mut item =
             Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg);
diff --git a/src/librustdoc/docfs.rs b/src/librustdoc/docfs.rs
index be066bdafa1..d58b8dc6ad4 100644
--- a/src/librustdoc/docfs.rs
+++ b/src/librustdoc/docfs.rs
@@ -2,18 +2,20 @@
 //!
 //! On Windows this indirects IO into threads to work around performance issues
 //! with Defender (and other similar virus scanners that do blocking operations).
-//! On other platforms this is a thin shim to fs.
 //!
 //! Only calls needed to permit this workaround have been abstracted: thus
 //! fs::read is still done directly via the fs module; if in future rustdoc
 //! needs to read-after-write from a file, then it would be added to this
 //! abstraction.
 
+use std::cmp::max;
 use std::fs;
 use std::io;
 use std::path::{Path, PathBuf};
 use std::string::ToString;
 use std::sync::mpsc::Sender;
+use std::thread::available_parallelism;
+use threadpool::ThreadPool;
 
 pub(crate) trait PathError {
     fn new<S, P: AsRef<Path>>(e: S, path: P) -> Self
@@ -24,11 +26,21 @@ pub(crate) trait PathError {
 pub(crate) struct DocFS {
     sync_only: bool,
     errors: Option<Sender<String>>,
+    pool: ThreadPool,
 }
 
 impl DocFS {
     pub(crate) fn new(errors: Sender<String>) -> DocFS {
-        DocFS { sync_only: false, errors: Some(errors) }
+        const MINIMUM_NB_THREADS: usize = 2;
+        DocFS {
+            sync_only: false,
+            errors: Some(errors),
+            pool: ThreadPool::new(
+                available_parallelism()
+                    .map(|nb| max(nb.get(), MINIMUM_NB_THREADS))
+                    .unwrap_or(MINIMUM_NB_THREADS),
+            ),
+        }
     }
 
     pub(crate) fn set_sync_only(&mut self, sync_only: bool) {
@@ -54,12 +66,11 @@ impl DocFS {
     where
         E: PathError,
     {
-        #[cfg(windows)]
         if !self.sync_only {
             // A possible future enhancement after more detailed profiling would
             // be to create the file sync so errors are reported eagerly.
             let sender = self.errors.clone().expect("can't write after closing");
-            rayon::spawn(move || {
+            self.pool.execute(move || {
                 fs::write(&path, contents).unwrap_or_else(|e| {
                     sender.send(format!("\"{}\": {}", path.display(), e)).unwrap_or_else(|_| {
                         panic!("failed to send error on \"{}\"", path.display())
@@ -70,9 +81,12 @@ impl DocFS {
             fs::write(&path, contents).map_err(|e| E::new(e, path))?;
         }
 
-        #[cfg(not(windows))]
-        fs::write(&path, contents).map_err(|e| E::new(e, path))?;
-
         Ok(())
     }
 }
+
+impl Drop for DocFS {
+    fn drop(&mut self) {
+        self.pool.join();
+    }
+}
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 9cf84acc79f..aaa83ecce48 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1057,6 +1057,16 @@ impl Tester for Collector {
                     Ignore::Some(ref ignores) => ignores.iter().any(|s| target_str.contains(s)),
                 },
                 ignore_message: None,
+                #[cfg(not(bootstrap))]
+                source_file: "",
+                #[cfg(not(bootstrap))]
+                start_line: 0,
+                #[cfg(not(bootstrap))]
+                start_col: 0,
+                #[cfg(not(bootstrap))]
+                end_line: 0,
+                #[cfg(not(bootstrap))]
+                end_col: 0,
                 // compiler failures are test failures
                 should_panic: test::ShouldPanic::No,
                 compile_fail: config.compile_fail,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 024ea62c31a..f2b9c0bcf3e 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -771,6 +771,12 @@ pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Cont
         .or_else(|| cache.external_paths.get(&did))
         else { return String::new() };
     let mut buf = Buffer::new();
+    let fqp = if *shortty == ItemType::Primitive {
+        // primitives are documented in a crate, but not actually part of it
+        &fqp[fqp.len() - 1..]
+    } else {
+        &fqp
+    };
     if let &Some(UrlFragment::Item(id)) = fragment {
         write!(buf, "{} ", cx.tcx().def_descr(id));
         for component in fqp {
@@ -1474,7 +1480,7 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
                 debug!("path={:?}", path);
                 // modified from `resolved_path()` to work with `DefPathData`
                 let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
-                let anchor = anchor(vis_did, last_name, cx).to_string();
+                let anchor = anchor(vis_did, last_name, cx);
 
                 let mut s = "pub(in ".to_owned();
                 for seg in &path.data[..path.data.len() - 1] {
@@ -1496,9 +1502,9 @@ pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>(
     tcx: TyCtxt<'tcx>,
     item_did: DefId,
 ) -> impl fmt::Display + 'a + Captures<'tcx> {
-    let to_print = match visibility {
-        None => String::new(),
-        Some(ty::Visibility::Public) => "pub ".to_owned(),
+    let to_print: Cow<'static, str> = match visibility {
+        None => "".into(),
+        Some(ty::Visibility::Public) => "pub ".into(),
         Some(ty::Visibility::Restricted(vis_did)) => {
             // FIXME(camelid): This may not work correctly if `item_did` is a module.
             //                 However, rustdoc currently never displays a module's
@@ -1506,17 +1512,17 @@ pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>(
             let parent_module = find_nearest_parent_module(tcx, item_did);
 
             if vis_did.is_crate_root() {
-                "pub(crate) ".to_owned()
+                "pub(crate) ".into()
             } else if parent_module == Some(vis_did) {
                 // `pub(in foo)` where `foo` is the parent module
                 // is the same as no visibility modifier
-                String::new()
+                "".into()
             } else if parent_module.and_then(|parent| find_nearest_parent_module(tcx, parent))
                 == Some(vis_did)
             {
-                "pub(super) ".to_owned()
+                "pub(super) ".into()
             } else {
-                format!("pub(in {}) ", tcx.def_path_str(vis_did))
+                format!("pub(in {}) ", tcx.def_path_str(vis_did)).into()
             }
         }
     };
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 2c9fc4e3ca3..c099d0e4f3f 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -65,23 +65,6 @@ pub(crate) fn render_item_decl_with_highlighting(src: &str, out: &mut Buffer) {
     write!(out, "</pre>");
 }
 
-/// Highlights `src` as a source code page, returning the HTML output.
-pub(crate) fn render_source_with_highlighting(
-    src: &str,
-    out: &mut Buffer,
-    line_numbers: Buffer,
-    href_context: HrefContext<'_, '_>,
-    decoration_info: DecorationInfo,
-    extra: Option<&str>,
-) {
-    write_header(out, "", Some(line_numbers), Tooltip::None);
-    if let Some(extra) = extra {
-        out.push_str(extra);
-    }
-    write_code(out, src, Some(href_context), Some(decoration_info));
-    write_footer(out, None);
-}
-
 fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, tooltip: Tooltip) {
     write!(
         out,
@@ -143,8 +126,8 @@ fn can_merge(class1: Option<Class>, class2: Option<Class>, text: &str) -> bool {
 
 /// This type is used as a conveniency to prevent having to pass all its fields as arguments into
 /// the various functions (which became its methods).
-struct TokenHandler<'a, 'tcx> {
-    out: &'a mut Buffer,
+struct TokenHandler<'a, 'tcx, F: Write> {
+    out: &'a mut F,
     /// It contains the closing tag and the associated `Class`.
     closing_tags: Vec<(&'static str, Class)>,
     /// This is used because we don't automatically generate the closing tag on `ExitSpan` in
@@ -159,7 +142,7 @@ struct TokenHandler<'a, 'tcx> {
     href_context: Option<HrefContext<'a, 'tcx>>,
 }
 
-impl<'a, 'tcx> TokenHandler<'a, 'tcx> {
+impl<'a, 'tcx, F: Write> TokenHandler<'a, 'tcx, F> {
     fn handle_exit_span(&mut self) {
         // We can't get the last `closing_tags` element using `pop()` because `closing_tags` is
         // being used in `write_pending_elems`.
@@ -211,7 +194,7 @@ impl<'a, 'tcx> TokenHandler<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Drop for TokenHandler<'a, 'tcx> {
+impl<'a, 'tcx, F: Write> Drop for TokenHandler<'a, 'tcx, F> {
     /// When leaving, we need to flush all pending data to not have missing content.
     fn drop(&mut self) {
         if self.pending_exit_span.is_some() {
@@ -233,8 +216,8 @@ impl<'a, 'tcx> Drop for TokenHandler<'a, 'tcx> {
 /// item definition.
 ///
 /// More explanations about spans and how we use them here are provided in the
-fn write_code(
-    out: &mut Buffer,
+pub(super) fn write_code(
+    out: &mut impl Write,
     src: &str,
     href_context: Option<HrefContext<'_, '_>>,
     decoration_info: Option<DecorationInfo>,
@@ -883,7 +866,7 @@ impl<'src> Classifier<'src> {
 /// Called when we start processing a span of text that should be highlighted.
 /// The `Class` argument specifies how it should be highlighted.
 fn enter_span(
-    out: &mut Buffer,
+    out: &mut impl Write,
     klass: Class,
     href_context: &Option<HrefContext<'_, '_>>,
 ) -> &'static str {
@@ -894,8 +877,8 @@ fn enter_span(
 }
 
 /// Called at the end of a span of highlighted text.
-fn exit_span(out: &mut Buffer, closing_tag: &str) {
-    out.write_str(closing_tag);
+fn exit_span(out: &mut impl Write, closing_tag: &str) {
+    out.write_str(closing_tag).unwrap();
 }
 
 /// Called for a span of text. If the text should be highlighted differently
@@ -915,7 +898,7 @@ fn exit_span(out: &mut Buffer, closing_tag: &str) {
 /// will then try to find this `span` in the `span_correspondance_map`. If found, it'll then
 /// generate a link for this element (which corresponds to where its definition is located).
 fn string<T: Display>(
-    out: &mut Buffer,
+    out: &mut impl Write,
     text: T,
     klass: Option<Class>,
     href_context: &Option<HrefContext<'_, '_>>,
@@ -923,7 +906,7 @@ fn string<T: Display>(
 ) {
     if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag)
     {
-        out.write_str(closing_tag);
+        out.write_str(closing_tag).unwrap();
     }
 }
 
@@ -937,7 +920,7 @@ fn string<T: Display>(
 ///   in `span_map.rs::collect_spans_and_sources`. If it cannot retrieve the information, then it's
 ///   the same as the second point (`klass` is `Some` but doesn't have a [`rustc_span::Span`]).
 fn string_without_closing_tag<T: Display>(
-    out: &mut Buffer,
+    out: &mut impl Write,
     text: T,
     klass: Option<Class>,
     href_context: &Option<HrefContext<'_, '_>>,
@@ -945,16 +928,16 @@ fn string_without_closing_tag<T: Display>(
 ) -> Option<&'static str> {
     let Some(klass) = klass
     else {
-        write!(out, "{}", text);
+        write!(out, "{}", text).unwrap();
         return None;
     };
     let Some(def_span) = klass.get_span()
     else {
         if !open_tag {
-            write!(out, "{}", text);
+            write!(out, "{}", text).unwrap();
             return None;
         }
-        write!(out, "<span class=\"{}\">{}", klass.as_html(), text);
+        write!(out, "<span class=\"{}\">{}", klass.as_html(), text).unwrap();
         return Some("</span>");
     };
 
@@ -1009,28 +992,28 @@ fn string_without_closing_tag<T: Display>(
             if !open_tag {
                 // We're already inside an element which has the same klass, no need to give it
                 // again.
-                write!(out, "<a href=\"{}\">{}", href, text_s);
+                write!(out, "<a href=\"{}\">{}", href, text_s).unwrap();
             } else {
                 let klass_s = klass.as_html();
                 if klass_s.is_empty() {
-                    write!(out, "<a href=\"{}\">{}", href, text_s);
+                    write!(out, "<a href=\"{}\">{}", href, text_s).unwrap();
                 } else {
-                    write!(out, "<a class=\"{}\" href=\"{}\">{}", klass_s, href, text_s);
+                    write!(out, "<a class=\"{}\" href=\"{}\">{}", klass_s, href, text_s).unwrap();
                 }
             }
             return Some("</a>");
         }
     }
     if !open_tag {
-        write!(out, "{}", text_s);
+        write!(out, "{}", text_s).unwrap();
         return None;
     }
     let klass_s = klass.as_html();
     if klass_s.is_empty() {
-        write!(out, "{}", text_s);
+        out.write_str(&text_s).unwrap();
         Some("")
     } else {
-        write!(out, "<span class=\"{}\">{}", klass_s, text_s);
+        write!(out, "<span class=\"{}\">{}", klass_s, text_s).unwrap();
         Some("</span>")
     }
 }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index fe446ae3c16..fd81a21f5a9 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -556,7 +556,15 @@ fn check_if_allowed_tag(t: &Tag<'_>) -> bool {
 }
 
 fn is_forbidden_tag(t: &Tag<'_>) -> bool {
-    matches!(t, Tag::CodeBlock(_) | Tag::Table(_) | Tag::TableHead | Tag::TableRow | Tag::TableCell)
+    matches!(
+        t,
+        Tag::CodeBlock(_)
+            | Tag::Table(_)
+            | Tag::TableHead
+            | Tag::TableRow
+            | Tag::TableCell
+            | Tag::FootnoteDefinition(_)
+    )
 }
 
 impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
@@ -589,6 +597,10 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
                     is_start = false;
                     check_if_allowed_tag(c)
                 }
+                Event::FootnoteReference(_) => {
+                    self.skipped_tags += 1;
+                    false
+                }
                 _ => true,
             };
             if !is_allowed_tag {
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 63cd0e04a28..ac5054ce1b6 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -352,7 +352,7 @@ impl<'tcx> Context<'tcx> {
                 },
             );
 
-            path = href.into_inner().to_string_lossy().to_string();
+            path = href.into_inner().to_string_lossy().into_owned();
 
             if let Some(c) = path.as_bytes().last() && *c != b'/' {
                 path.push('/');
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 577497868f6..7eb9c0b7cf5 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1,5 +1,6 @@
 use clean::AttributesExt;
 
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
@@ -28,8 +29,8 @@ use crate::formats::item_type::ItemType;
 use crate::formats::{AssocItemRender, Impl, RenderMode};
 use crate::html::escape::Escape;
 use crate::html::format::{
-    join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause,
-    visibility_print_with_space, Buffer, Ending, PrintWithSpace,
+    display_fn, join_with_double_colon, print_abi_with_space, print_constness_with_space,
+    print_where_clause, visibility_print_with_space, Buffer, Ending, PrintWithSpace,
 };
 use crate::html::layout::Page;
 use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
@@ -367,7 +368,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                         ..myitem.clone()
                     };
 
-                    let stab_tags = Some(extra_info_tags(&import_item, item, cx.tcx()));
+                    let stab_tags = Some(extra_info_tags(&import_item, item, cx.tcx()).to_string());
                     stab_tags
                 } else {
                     None
@@ -461,42 +462,62 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
 
 /// Render the stability, deprecation and portability tags that are displayed in the item's summary
 /// at the module level.
-fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) -> String {
-    let mut tags = String::new();
-
-    fn tag_html(class: &str, title: &str, contents: &str) -> String {
-        format!(r#"<span class="stab {}" title="{}">{}</span>"#, class, Escape(title), contents)
-    }
-
-    // The trailing space after each tag is to space it properly against the rest of the docs.
-    if let Some(depr) = &item.deprecation(tcx) {
-        let message = if stability::deprecation_in_effect(depr) {
-            "Deprecated"
-        } else {
-            "Deprecation planned"
-        };
-        tags += &tag_html("deprecated", "", message);
-    }
+fn extra_info_tags<'a, 'tcx: 'a>(
+    item: &'a clean::Item,
+    parent: &'a clean::Item,
+    tcx: TyCtxt<'tcx>,
+) -> impl fmt::Display + 'a + Captures<'tcx> {
+    display_fn(move |f| {
+        fn tag_html<'a>(
+            class: &'a str,
+            title: &'a str,
+            contents: &'a str,
+        ) -> impl fmt::Display + 'a {
+            display_fn(move |f| {
+                write!(
+                    f,
+                    r#"<span class="stab {}" title="{}">{}</span>"#,
+                    class,
+                    Escape(title),
+                    contents
+                )
+            })
+        }
 
-    // The "rustc_private" crates are permanently unstable so it makes no sense
-    // to render "unstable" everywhere.
-    if item.stability(tcx).as_ref().map(|s| s.is_unstable() && s.feature != sym::rustc_private)
-        == Some(true)
-    {
-        tags += &tag_html("unstable", "", "Experimental");
-    }
+        // The trailing space after each tag is to space it properly against the rest of the docs.
+        if let Some(depr) = &item.deprecation(tcx) {
+            let message = if stability::deprecation_in_effect(depr) {
+                "Deprecated"
+            } else {
+                "Deprecation planned"
+            };
+            write!(f, "{}", tag_html("deprecated", "", message))?;
+        }
 
-    let cfg = match (&item.cfg, parent.cfg.as_ref()) {
-        (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
-        (cfg, _) => cfg.as_deref().cloned(),
-    };
+        // The "rustc_private" crates are permanently unstable so it makes no sense
+        // to render "unstable" everywhere.
+        if item.stability(tcx).as_ref().map(|s| s.is_unstable() && s.feature != sym::rustc_private)
+            == Some(true)
+        {
+            write!(f, "{}", tag_html("unstable", "", "Experimental"))?;
+        }
 
-    debug!("Portability name={:?} {:?} - {:?} = {:?}", item.name, item.cfg, parent.cfg, cfg);
-    if let Some(ref cfg) = cfg {
-        tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html());
-    }
+        let cfg = match (&item.cfg, parent.cfg.as_ref()) {
+            (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
+            (cfg, _) => cfg.as_deref().cloned(),
+        };
 
-    tags
+        debug!("Portability name={:?} {:?} - {:?} = {:?}", item.name, item.cfg, parent.cfg, cfg);
+        if let Some(ref cfg) = cfg {
+            write!(
+                f,
+                "{}",
+                tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html())
+            )
+        } else {
+            Ok(())
+        }
+    })
 }
 
 fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) {
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 146221f5806..08a0e1c377e 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -486,7 +486,7 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>(
     }
 
     // First, check if it's "Self".
-    let arg = if let Some(self_) = self_ {
+    let mut arg = if let Some(self_) = self_ {
         match &*arg {
             Type::BorrowedRef { type_, .. } if type_.is_self_type() => self_,
             type_ if type_.is_self_type() => self_,
@@ -496,11 +496,16 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>(
         arg
     };
 
+    // strip references from the argument type
+    while let Type::BorrowedRef { type_, .. } = &*arg {
+        arg = &*type_;
+    }
+
     // If this argument is a type parameter and not a trait bound or a type, we need to look
     // for its bounds.
     if let Type::Generic(arg_s) = *arg {
         // First we check if the bounds are in a `where` predicate...
-        if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
+        for where_pred in generics.where_predicates.iter().filter(|g| match g {
             WherePredicate::BoundPredicate { ty: Type::Generic(ty_s), .. } => *ty_s == arg_s,
             _ => false,
         }) {
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 2c90bf4fadc..1d298f52f75 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -1,12 +1,14 @@
 use crate::clean;
 use crate::docfs::PathError;
 use crate::error::Error;
+use crate::html::format;
 use crate::html::format::Buffer;
 use crate::html::highlight;
 use crate::html::layout;
 use crate::html::render::Context;
 use crate::visit::DocVisitor;
 
+use askama::Template;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::TyCtxt;
@@ -16,6 +18,7 @@ use rustc_span::source_map::FileName;
 use std::cell::RefCell;
 use std::ffi::OsStr;
 use std::fs;
+use std::ops::RangeInclusive;
 use std::path::{Component, Path, PathBuf};
 use std::rc::Rc;
 
@@ -85,7 +88,7 @@ impl LocalSourcesCollector<'_, '_> {
             },
         );
 
-        let mut href = href.into_inner().to_string_lossy().to_string();
+        let mut href = href.into_inner().to_string_lossy().into_owned();
         if let Some(c) = href.as_bytes().last() && *c != b'/' {
             href.push('/');
         }
@@ -299,39 +302,32 @@ pub(crate) fn print_src(
     decoration_info: highlight::DecorationInfo,
     source_context: SourceContext,
 ) {
+    #[derive(Template)]
+    #[template(path = "source.html")]
+    struct Source<Code: std::fmt::Display> {
+        embedded: bool,
+        needs_expansion: bool,
+        lines: RangeInclusive<usize>,
+        code_html: Code,
+    }
     let lines = s.lines().count();
-    let mut line_numbers = Buffer::empty_from(buf);
-    let extra;
-    line_numbers.write_str("<pre class=\"src-line-numbers\">");
+    let (embedded, needs_expansion, lines) = match source_context {
+        SourceContext::Standalone => (false, false, 1..=lines),
+        SourceContext::Embedded { offset, needs_expansion } => {
+            (true, needs_expansion, (1 + offset)..=(lines + offset))
+        }
+    };
     let current_href = context
         .href_from_span(clean::Span::new(file_span), false)
         .expect("only local crates should have sources emitted");
-    match source_context {
-        SourceContext::Standalone => {
-            extra = None;
-            for line in 1..=lines {
-                writeln!(line_numbers, "<a href=\"#{line}\" id=\"{line}\">{line}</a>")
-            }
-        }
-        SourceContext::Embedded { offset, needs_expansion } => {
-            extra = if needs_expansion {
-                Some(r#"<button class="expand">&varr;</button>"#)
-            } else {
-                None
-            };
-            for line_number in 1..=lines {
-                let line = line_number + offset;
-                writeln!(line_numbers, "<span>{line}</span>")
-            }
-        }
-    }
-    line_numbers.write_str("</pre>");
-    highlight::render_source_with_highlighting(
-        s,
-        buf,
-        line_numbers,
-        highlight::HrefContext { context, file_span, root_path, current_href },
-        decoration_info,
-        extra,
-    );
+    let code = format::display_fn(move |fmt| {
+        highlight::write_code(
+            fmt,
+            s,
+            Some(highlight::HrefContext { context, file_span, root_path, current_href }),
+            Some(decoration_info),
+        );
+        Ok(())
+    });
+    Source { embedded, needs_expansion, lines, code_html: code }.render_into(buf).unwrap();
 }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index c71ce2c3001..36ff20e299e 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1202,28 +1202,42 @@ function initSearch(rawSearchIndex) {
          * @param {Row} row
          * @param {QueryElement} elem    - The element from the parsed query.
          * @param {integer} typeFilter
+         * @param {Array<integer>} skipPositions - Do not return one of these positions.
          *
-         * @return {integer} - Returns an edit distance to the best match. If there is no
-         *                      match, returns `maxEditDistance + 1`.
+         * @return {dist: integer, position: integer} - Returns an edit distance to the best match.
+         *                                              If there is no match, returns
+         *                                              `maxEditDistance + 1` and position: -1.
          */
-        function findArg(row, elem, typeFilter, maxEditDistance) {
+        function findArg(row, elem, typeFilter, maxEditDistance, skipPositions) {
             let dist = maxEditDistance + 1;
+            let position = -1;
 
             if (row && row.type && row.type.inputs && row.type.inputs.length > 0) {
+                let i = 0;
                 for (const input of row.type.inputs) {
-                    if (!typePassesFilter(typeFilter, input.ty)) {
+                    if (!typePassesFilter(typeFilter, input.ty) ||
+                        skipPositions.indexOf(i) !== -1) {
+                        i += 1;
                         continue;
                     }
-                    dist = Math.min(
-                        dist,
-                        checkType(input, elem, parsedQuery.literalSearch, maxEditDistance)
+                    const typeDist = checkType(
+                        input,
+                        elem,
+                        parsedQuery.literalSearch,
+                        maxEditDistance
                     );
-                    if (dist === 0) {
-                        return 0;
+                    if (typeDist === 0) {
+                        return {dist: 0, position: i};
+                    }
+                    if (typeDist < dist) {
+                        dist = typeDist;
+                        position = i;
                     }
+                    i += 1;
                 }
             }
-            return parsedQuery.literalSearch ? maxEditDistance + 1 : dist;
+            dist = parsedQuery.literalSearch ? maxEditDistance + 1 : dist;
+            return {dist, position};
         }
 
         /**
@@ -1232,29 +1246,43 @@ function initSearch(rawSearchIndex) {
          * @param {Row} row
          * @param {QueryElement} elem   - The element from the parsed query.
          * @param {integer} typeFilter
+         * @param {Array<integer>} skipPositions - Do not return one of these positions.
          *
-         * @return {integer} - Returns an edit distance to the best match. If there is no
-         *                      match, returns `maxEditDistance + 1`.
+         * @return {dist: integer, position: integer} - Returns an edit distance to the best match.
+         *                                              If there is no match, returns
+         *                                              `maxEditDistance + 1` and position: -1.
          */
-        function checkReturned(row, elem, typeFilter, maxEditDistance) {
+        function checkReturned(row, elem, typeFilter, maxEditDistance, skipPositions) {
             let dist = maxEditDistance + 1;
+            let position = -1;
 
             if (row && row.type && row.type.output.length > 0) {
                 const ret = row.type.output;
+                let i = 0;
                 for (const ret_ty of ret) {
-                    if (!typePassesFilter(typeFilter, ret_ty.ty)) {
+                    if (!typePassesFilter(typeFilter, ret_ty.ty) ||
+                        skipPositions.indexOf(i) !== -1) {
+                        i += 1;
                         continue;
                     }
-                    dist = Math.min(
-                        dist,
-                        checkType(ret_ty, elem, parsedQuery.literalSearch, maxEditDistance)
+                    const typeDist = checkType(
+                        ret_ty,
+                        elem,
+                        parsedQuery.literalSearch,
+                        maxEditDistance
                     );
-                    if (dist === 0) {
-                        return 0;
+                    if (typeDist === 0) {
+                        return {dist: 0, position: i};
                     }
+                    if (typeDist < dist) {
+                        dist = typeDist;
+                        position = i;
+                    }
+                    i += 1;
                 }
             }
-            return parsedQuery.literalSearch ? maxEditDistance + 1 : dist;
+            dist = parsedQuery.literalSearch ? maxEditDistance + 1 : dist;
+            return {dist, position};
         }
 
         function checkPath(contains, ty, maxEditDistance) {
@@ -1455,13 +1483,13 @@ function initSearch(rawSearchIndex) {
             const fullId = row.id;
             const searchWord = searchWords[pos];
 
-            const in_args = findArg(row, elem, parsedQuery.typeFilter, maxEditDistance);
-            const returned = checkReturned(row, elem, parsedQuery.typeFilter, maxEditDistance);
+            const in_args = findArg(row, elem, parsedQuery.typeFilter, maxEditDistance, []);
+            const returned = checkReturned(row, elem, parsedQuery.typeFilter, maxEditDistance, []);
 
             // path_dist is 0 because no parent path information is currently stored
             // in the search index
-            addIntoResults(results_in_args, fullId, pos, -1, in_args, 0, maxEditDistance);
-            addIntoResults(results_returned, fullId, pos, -1, returned, 0, maxEditDistance);
+            addIntoResults(results_in_args, fullId, pos, -1, in_args.dist, 0, maxEditDistance);
+            addIntoResults(results_returned, fullId, pos, -1, returned.dist, 0, maxEditDistance);
 
             if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
                 return;
@@ -1534,12 +1562,20 @@ function initSearch(rawSearchIndex) {
 
             // If the result is too "bad", we return false and it ends this search.
             function checkArgs(elems, callback) {
+                const skipPositions = [];
                 for (const elem of elems) {
                     // There is more than one parameter to the query so all checks should be "exact"
-                    const dist = callback(row, elem, NO_TYPE_FILTER, maxEditDistance);
+                    const { dist, position } = callback(
+                        row,
+                        elem,
+                        NO_TYPE_FILTER,
+                        maxEditDistance,
+                        skipPositions
+                    );
                     if (dist <= 1) {
                         nbDist += 1;
                         totalDist += dist;
+                        skipPositions.push(position);
                     } else {
                         return false;
                     }
@@ -1597,9 +1633,17 @@ function initSearch(rawSearchIndex) {
                             row,
                             elem,
                             parsedQuery.typeFilter,
+                            maxEditDistance,
+                            []
+                        );
+                        addIntoResults(
+                            results_others,
+                            row.id,
+                            i,
+                            -1,
+                            in_returned.dist,
                             maxEditDistance
                         );
-                        addIntoResults(results_others, row.id, i, -1, in_returned, maxEditDistance);
                     }
                 }
             } else if (parsedQuery.foundElems > 0) {
diff --git a/src/librustdoc/html/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md
index 72c516c93eb..0281b1c47f8 100644
--- a/src/librustdoc/html/templates/STYLE.md
+++ b/src/librustdoc/html/templates/STYLE.md
@@ -1,12 +1,12 @@
 # Style for Templates
 
-This directory has templates in the [Tera templating language](teradoc), which is very
-similar to [Jinja2](jinjadoc) and [Django](djangodoc) templates, and also to [Askama](askamadoc).
+This directory has templates in the [Tera templating language][teradoc], which is very
+similar to [Jinja2][jinjadoc] and [Django][djangodoc] templates, and also to [Askama][askamadoc].
 
 [teradoc]: https://tera.netlify.app/docs/#templates
-[jinjadoc]: https://jinja.palletsprojects.com/en/3.0.x/templates/
-[djangodoc]: https://docs.djangoproject.com/en/3.2/topics/templates/
-[askamadoc]: https://docs.rs/askama/0.10.5/askama/
+[jinjadoc]: https://jinja.palletsprojects.com/en/3.1.x/templates/
+[djangodoc]: https://docs.djangoproject.com/en/4.1/topics/templates/
+[askamadoc]: https://docs.rs/askama/latest/askama/
 
 We want our rendered output to have as little unnecessary whitespace as
 possible, so that pages load quickly. To achieve that we use Tera's
@@ -30,8 +30,8 @@ contents don't necessarily need a new line.
 
 Askama templates support quite sophisticated control flow. To keep our templates
 simple and understandable, we use only a subset: `if` and `for`. In particular
-we avoid [assignments in the template logic](assignments) and [Askama
-macros](macros). This also may make things easier if we switch to a different
+we avoid [assignments in the template logic][assignments] and [Askama
+macros][macros]. This also may make things easier if we switch to a different
 Jinja-style template system, like Askama, in the future.
 
 [assignments]: https://djc.github.io/askama/template_syntax.html#assignments
diff --git a/src/librustdoc/html/templates/short_item_info.html b/src/librustdoc/html/templates/short_item_info.html
index e3125af0e47..75d155e91c2 100644
--- a/src/librustdoc/html/templates/short_item_info.html
+++ b/src/librustdoc/html/templates/short_item_info.html
@@ -2,7 +2,7 @@
     {% when Self::Deprecation with { message } %}
         <div class="stab deprecated"> {# #}
             <span class="emoji">👎</span> {# #}
-            <span>{{message}}</span> {# #}
+            <span>{{message|safe}}</span> {# #}
         </div> {# #}
     {% when Self::Unstable with { feature, tracking } %}
         <div class="stab unstable"> {# #}
diff --git a/src/librustdoc/html/templates/source.html b/src/librustdoc/html/templates/source.html
new file mode 100644
index 00000000000..a224ff12f44
--- /dev/null
+++ b/src/librustdoc/html/templates/source.html
@@ -0,0 +1,19 @@
+<div class="example-wrap"> {# #}
+    <pre class="src-line-numbers">
+        {% for line in lines.clone() %}
+            {% if embedded %}
+                <span>{{line|safe}}</span>
+            {%~ else %}
+                <a href="#{{line|safe}}" id="{{line|safe}}">{{line|safe}}</a>
+            {%~ endif %}
+        {% endfor %}
+    </pre> {# #}
+    <pre class="rust"> {# #}
+        <code>
+            {% if needs_expansion %}
+                <button class="expand">&varr;</button>
+            {% endif %}
+            {{code_html|safe}}
+        </code> {# #}
+    </pre> {# #}
+</div>
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 358f6ad566c..6ed7b989999 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -286,7 +286,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             split.next().map(|f|  Symbol::intern(f)).ok_or_else(no_res)?;
         let path = split
             .next()
-            .map(|f| f.to_owned())
             // If there's no third component, we saw `[a::b]` before and it failed to resolve.
             // So there's no partial res.
             .ok_or_else(no_res)?;
@@ -429,7 +428,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         let item_name = Symbol::intern(item_str);
         let path_root = split
             .next()
-            .map(|f| f.to_owned())
             // If there's no `::`, it's not an associated item.
             // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
             .ok_or_else(|| {
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index e09a68069e8..060062db002 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -265,10 +265,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             return false;
         }
 
-        if !self.view_item_stack.insert(res_did) {
-            return false;
-        }
-
         if !please_inline &&
             let mut visitor = OneLevelVisitor::new(self.cx.tcx.hir(), res_did) &&
             let Some(item) = visitor.find_target(self.cx.tcx, def_id.to_def_id(), path) &&
@@ -285,6 +281,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             return false;
         }
 
+        if !self.view_item_stack.insert(res_did) {
+            return false;
+        }
+
         let ret = match tcx.hir().get_by_def_id(res_did) {
             Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => {
                 let prev = mem::replace(&mut self.inlining, true);
diff --git a/src/stage0.json b/src/stage0.json
index 46f70b1ef4b..9250d9c2804 100644
--- a/src/stage0.json
+++ b/src/stage0.json
@@ -17,409 +17,409 @@
     "tool is executed."
   ],
   "compiler": {
-    "date": "2023-01-25",
+    "date": "2023-03-07",
     "version": "beta"
   },
   "rustfmt": {
-    "date": "2023-01-30",
+    "date": "2023-03-07",
     "version": "nightly"
   },
   "checksums_sha256": {
-    "dist/2023-01-25/cargo-beta-aarch64-apple-darwin.tar.gz": "323f3c4c41892765b24201aae83a54fcaef08e47b9b2912a2680528c6ed4f8f8",
-    "dist/2023-01-25/cargo-beta-aarch64-apple-darwin.tar.xz": "2039157d9100ccadf4d3596f5d7b052e10ff997b59ac7619999969794fc51eae",
-    "dist/2023-01-25/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "ac3c88c99aed8d4547f8b0f857ec3538456f10223411580278eed10f6e2be30b",
-    "dist/2023-01-25/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "27b11ea3c67f202e61b5e7394d36bedc7f1b054ca53d68e53ccd7bacf77b4af3",
-    "dist/2023-01-25/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "4d6d1d47d34e8042aa978fe5a6b5b8984d6626d38731081db2d5b413d5b844f4",
-    "dist/2023-01-25/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "a50e473aa6b6bffd84a719aec602d4bc19f03ccb0ee5f26340eb466501cb2970",
-    "dist/2023-01-25/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "a043def73a5c72d515c3d7dabe09022c353b047e7a4e4e13e9b17da9b30f8828",
-    "dist/2023-01-25/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "a63a8915409df4ae5d76d530b46cb7e83b6e6ca79790fa095d899e33773124a0",
-    "dist/2023-01-25/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "9c0c413187f1f1e0f1b6f1b66af0bd1b264d94f73439f6df24f476ee1c6c04fe",
-    "dist/2023-01-25/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "cb79e76beb989a3e4ffd1461817ad2dd0602aca3bce1a2e54cccc1bbb518a303",
-    "dist/2023-01-25/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "d57c5806a13b498768b53a053c7eb17e8becb19ea5fc9561a2a600dafea32056",
-    "dist/2023-01-25/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "33f35d8c2f5fcd5fa7928f2186a8b2417040e01462152430bae978d8d5a661cd",
-    "dist/2023-01-25/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "80ba79da61f82dc760a9dd7bfdfde29fefcab4ae94917cbf5d908332f93061d3",
-    "dist/2023-01-25/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "a8e48c6345b0e195ea58d6237a247b0d20c8d128af1b12813430806b9a340d5b",
-    "dist/2023-01-25/cargo-beta-i686-pc-windows-gnu.tar.gz": "052e2c0ff954d66e40101dc075bdd19fdb0befcbfdbc26dd94093bc4147c65cc",
-    "dist/2023-01-25/cargo-beta-i686-pc-windows-gnu.tar.xz": "94681fbbeb12de4b97b0a5a0206204c41b16c3de1c7c3262e1488f00b22aeb51",
-    "dist/2023-01-25/cargo-beta-i686-pc-windows-msvc.tar.gz": "3c0c2205e97136ac5e13b3c89d745af24afc60e6b5adc24abf22755d8d0007a1",
-    "dist/2023-01-25/cargo-beta-i686-pc-windows-msvc.tar.xz": "9ccf1a81d524fbac3f859c0185421936b97ae565164c12ed32e6a39052eac695",
-    "dist/2023-01-25/cargo-beta-i686-unknown-linux-gnu.tar.gz": "68749447a45ada6bb6e06488e3d58ecca7939d3c77dc40c22f22d7257eae247c",
-    "dist/2023-01-25/cargo-beta-i686-unknown-linux-gnu.tar.xz": "6b8942c01d1b8fd1f1f399b7f63db409a30df240b5aca5cf34e3166adafb5053",
-    "dist/2023-01-25/cargo-beta-mips-unknown-linux-gnu.tar.gz": "7f8fcf5d25353dac5d2cd6ad04b20da19b2dbccd25a977e8122d85724a632392",
-    "dist/2023-01-25/cargo-beta-mips-unknown-linux-gnu.tar.xz": "91d0ec836e2941287ac28a753650e1b7b57364af58fdfedebe1fafea8612f1ac",
-    "dist/2023-01-25/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "171f40046f777d84fe5a4349d3565ad3485fdf075d8fbe194ca31ba2be9eeb1a",
-    "dist/2023-01-25/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "0521be760b2a1e6cc134bbe3473dea01a6d0fbf68b05995f41a75875d489eb60",
-    "dist/2023-01-25/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "ee7c39af31d09a42c5ce1151da6dc1147b5c1aceb0ea94cb3059bac49e72ba2a",
-    "dist/2023-01-25/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "dc8ddfc8bd305c3f1f4d7965b8bbd8b24235ef758c38a32b3d64b5879fab25d2",
-    "dist/2023-01-25/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "4757229750f44b3d523ef7a9c778d923113a8eb8b93ad97ef5e4f23a6f1e6a21",
-    "dist/2023-01-25/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "36911ebbdde86d90bca90b61b1b31f6ab054ff65907ac73a22d5ae09d061c444",
-    "dist/2023-01-25/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "8e4ce0a0743d301d056a1bafb4216ae96fd6cb06ca083216eaf7f3a21514e064",
-    "dist/2023-01-25/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "47e28a41670bbcc7a3787c68dcf72ffe42bfbc3e9f14418871ca814538f88180",
-    "dist/2023-01-25/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "7bcab6e25cd8208eb220839f6adb202dcd382e4bc32fa63b83c40fba330246b9",
-    "dist/2023-01-25/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "650bb4d6b51ef5293164642101395fbf6d9eedcaccccc8ff3e2be032d9e60316",
-    "dist/2023-01-25/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "fc779f539835c1f3e1e7d9c1eed932568a5e731888f766202279e9240dd20e36",
-    "dist/2023-01-25/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "b39ab17c34560266df7dc60b6cf5626758f8b28f7142b916f1f3399342e6e0ec",
-    "dist/2023-01-25/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "7b677b4a2cc59b3baebc1265f8a364879b2195905de1eb20f62b66e2fbfdbb08",
-    "dist/2023-01-25/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bceab89d3ae1ffd25fc155a7b3514c69e3962ce8f7727cc7e7c4b40f0c6eb3eb",
-    "dist/2023-01-25/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "d0522064a1994aa338d12f5ef68635f8804a2cb9151dd67771ae132e65560790",
-    "dist/2023-01-25/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "478fdff509a609e5310c54fa1e0eecbb3870a0636132dbcc71291e150c805828",
-    "dist/2023-01-25/cargo-beta-x86_64-apple-darwin.tar.gz": "cfb5bc9dcf4c85915e5c7e4a29e7f45c4e5de4a3535c75ce7c192c08511e0350",
-    "dist/2023-01-25/cargo-beta-x86_64-apple-darwin.tar.xz": "6b1f48ceebc916f9829f599fc815de2b8724873ce8a22ba058a2a1ac1df46295",
-    "dist/2023-01-25/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "60d119c084899f0a1d7661188756833118bc538d7e7298c72d1452b06e27ef62",
-    "dist/2023-01-25/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "801d03dfab7e8007a97d95c551b3a069e56371fe33fa4682e20fa50a8123bc20",
-    "dist/2023-01-25/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "269bdb128749d234e12b5795b90acc1a91bc0c338ed3be70ab2e62d476fcd055",
-    "dist/2023-01-25/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "88737cc19187a0752e45345eb286a5e9d500f9c71e03bb26737888fe42b350b5",
-    "dist/2023-01-25/cargo-beta-x86_64-unknown-freebsd.tar.gz": "146d1af37cce4b6eff9f99bb74ad33f2d91383a2b69dfdbd59ad54fc2dd44c49",
-    "dist/2023-01-25/cargo-beta-x86_64-unknown-freebsd.tar.xz": "9466a4417a1ea6a9ab03ea7d05f747a731ed0bf5545148a1c782c797dcff50a9",
-    "dist/2023-01-25/cargo-beta-x86_64-unknown-illumos.tar.gz": "f32fcd8a18047646865afc67f92d6edda54fbe3f4e9963aba2095e23295e6ce0",
-    "dist/2023-01-25/cargo-beta-x86_64-unknown-illumos.tar.xz": "25431bfe87d8c944225122d21ca4823cefe72b304b10933c628d5d2df13d5f5c",
-    "dist/2023-01-25/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "cd67e483efd3a9cca57523cee428cd9a5555ff93b057f7fef4178a3e2fd49309",
-    "dist/2023-01-25/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "45d578c09399495b67ac38358e4251e3d7a20e988428a1a5a1e39387d2664da8",
-    "dist/2023-01-25/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "f66eb2cf2c637b4822e2c326b4a57d63eb3c0b517ddb69ff57a45001bc0a110f",
-    "dist/2023-01-25/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "7a0817ef29d6511d4fd9dbbdf3e9a92635f076d9b0633cb55b325cebeee4efb9",
-    "dist/2023-01-25/cargo-beta-x86_64-unknown-netbsd.tar.gz": "1330a1b4f975b1d96692bdc4a6392ca87e8e99982768acefc2815e386b6f4e77",
-    "dist/2023-01-25/cargo-beta-x86_64-unknown-netbsd.tar.xz": "919e25bd54133f4a8cbbf09218415ca7a5041298b32181fa566c5d4a8bfd8b90",
-    "dist/2023-01-25/rust-std-beta-aarch64-apple-darwin.tar.gz": "3dcf5c58141e44d1c84f33f58ca4dd99edd277ef15a69fc6b94fbe7c67a27483",
-    "dist/2023-01-25/rust-std-beta-aarch64-apple-darwin.tar.xz": "a651af6487e2f3246075b984fffb4072338a559ff8e6c373289a6242c0ca3ea7",
-    "dist/2023-01-25/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "5e3d5aa50784ee63c6df03b07ac92649f76c40ac6fb49c24d97896814002697c",
-    "dist/2023-01-25/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "0ae7440c74cee87c25757159a5749014eecf77b2bcee7e1e71eb9249f917d725",
-    "dist/2023-01-25/rust-std-beta-aarch64-apple-ios.tar.gz": "a47acbecb37786773c5d80da5990298c5facad11151c9991796eedf80472b1d5",
-    "dist/2023-01-25/rust-std-beta-aarch64-apple-ios.tar.xz": "9168f9b1cea16a213249a1c452a59719234c145045ddc6ae1752ce4bdf02be41",
-    "dist/2023-01-25/rust-std-beta-aarch64-linux-android.tar.gz": "54fad0afeead88e1f33eaada03b14710052c6fa0b7130dd87463d3670f1d9fb3",
-    "dist/2023-01-25/rust-std-beta-aarch64-linux-android.tar.xz": "5fdd761ca88de80754cf3e1221db141204f79e6c2aa57c72c0879af3b87dd0f4",
-    "dist/2023-01-25/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "27196acc8f1ab9d6843b673835927c16d6730a8daf96b1f05959884ac53232fe",
-    "dist/2023-01-25/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "0ea12b5fade681173aa4795399710cf5ff21d58f5f2fe54eb8d2c7516ef387b8",
-    "dist/2023-01-25/rust-std-beta-aarch64-unknown-fuchsia.tar.gz": "7bd0d57ba438868635726bad30fea7a52a5c429e77329bf2977805872deb1be2",
-    "dist/2023-01-25/rust-std-beta-aarch64-unknown-fuchsia.tar.xz": "8520674b4e10a6948b25dc0c58369e921a68c48a7b961bae510ac36e5c29cfe8",
-    "dist/2023-01-25/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "67c5668ce3427245821e53ea976201ebc23d1cb3c1a35a0d725d935de303e8a6",
-    "dist/2023-01-25/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "38236c5e562995e1aadd25151513580a2a7c7828df3baec0e0cccc0f6a856c2a",
-    "dist/2023-01-25/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "a5453d21e3620701a957208c573d718872c3909c2c4f9e83be33e14d36677cda",
-    "dist/2023-01-25/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "751928d0f640e3b77e2fde9cda623c3e9b3bca7de742100fc1f48388e4d22d8d",
-    "dist/2023-01-25/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "5a036c4d9cbda730e6f2af8c4912506659d1e3065b4d72050cc5b18e442105ea",
-    "dist/2023-01-25/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "2adfb04a0700dd3503527a80eb5ee71733b0fa2dbe974650d450d4bc3b5c8b0e",
-    "dist/2023-01-25/rust-std-beta-aarch64-unknown-none.tar.gz": "a92fa3278a98de5ab93d1f487863453dbe60bb31158d027aaaef85adf1f62924",
-    "dist/2023-01-25/rust-std-beta-aarch64-unknown-none.tar.xz": "1c0e523505aa9dbc07ec867ff8527dde29a706868bb55694d62e31924429e235",
-    "dist/2023-01-25/rust-std-beta-aarch64-unknown-uefi.tar.gz": "4adaac4b13c8d8170b59913230ac9e313ae48400b314d2ce10c138631626728e",
-    "dist/2023-01-25/rust-std-beta-aarch64-unknown-uefi.tar.xz": "2a2178e4e55f35ea5147f66d36450f9694416c0fbae9b776f39f405a1ab31cbb",
-    "dist/2023-01-25/rust-std-beta-arm-linux-androideabi.tar.gz": "17e4384d3a229bc452897e26400016c70912feb7e6ac2991a256829c5b391148",
-    "dist/2023-01-25/rust-std-beta-arm-linux-androideabi.tar.xz": "e57afb560be9a93faf5f0f852eac5cf5b16e2c05383d995a4e6a249367ee4567",
-    "dist/2023-01-25/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "d5a7c8f2fd9c3a1baa573b805334e5446605d2aa4589262f67e321c0590ef19e",
-    "dist/2023-01-25/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "1e62c48781111afd20fb1e015a4f611c3a3301762fd9e64e49beeb6f2bd14c8d",
-    "dist/2023-01-25/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "9e62d990466900818533af63479758f01f6e914d6ccb7910639c6fbbd49ae803",
-    "dist/2023-01-25/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "e685b0f2acf33c2eb58ac1e1a526787ee9df2f0bd1a1850581cc681c41a3ef0e",
-    "dist/2023-01-25/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "7a02618c26f17076add562a9f8792d170fe60190d1868703936e37df3af882e4",
-    "dist/2023-01-25/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "d8988dd528dcc19742b703d44dff4ebcef71cec66eaae39768434d77e53557eb",
-    "dist/2023-01-25/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "882e8f09cf68f135a29e64d0eb50727e4ac56939c4cfbcc3d369b928be442099",
-    "dist/2023-01-25/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "7d9b1ebaf89cad6024f07543519dde11da15eab0e2de3df88543156e4a44c48f",
-    "dist/2023-01-25/rust-std-beta-armebv7r-none-eabi.tar.gz": "a7e73661652b1feb9b1f50d271ebeba2938c169c8add96add8a26ded3d8468f5",
-    "dist/2023-01-25/rust-std-beta-armebv7r-none-eabi.tar.xz": "2a80ab44cb2f2b9769f52b6ddc5ffa4c8994092b18a7fb3125cdfaecb4e1a578",
-    "dist/2023-01-25/rust-std-beta-armebv7r-none-eabihf.tar.gz": "f70b0f86c783cc771700dc1f59c43e53b0de2d57775fef5854cd97fde4406b11",
-    "dist/2023-01-25/rust-std-beta-armebv7r-none-eabihf.tar.xz": "07214e7295be853fc7859481fcf94a4b20cc3bc2c022bf1783ddea56e30f92de",
-    "dist/2023-01-25/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "72be8b0740b14edda6656d2b5cffc69dea01f9bad7fcc9202586a901376116b2",
-    "dist/2023-01-25/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "42fb2607f1c7402f4d32be981cb5c0755be2e36fd0296b3b2753eecae98e5cc3",
-    "dist/2023-01-25/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "ae9ec6f3c3444e5b14103db8c04b95597705fe44c68c253c75383b47da4094de",
-    "dist/2023-01-25/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "1e0f7f1ccf9e4f6cc010a096d01f3e6056f1d4b0d319f5699dc67cad2f889d4a",
-    "dist/2023-01-25/rust-std-beta-armv7-linux-androideabi.tar.gz": "6e8b70d2606902b369dfc263ee25343fa3c71c4081f03066822e9a2a260ac573",
-    "dist/2023-01-25/rust-std-beta-armv7-linux-androideabi.tar.xz": "e3f9052bc831ca0a9b38a3da3be846113c6ab2c4f320ecdba489f0eddfc7e47c",
-    "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "e858e836806f3641c2f1074e63ce88771cdf135bca36d7c0d3dec0d1a4c98f8e",
-    "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "becfe9addbca5bf2123d12e70007c16c036c79fb299de2ce8da067d0f21b0f74",
-    "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "eef38b595752add74cf3bd29326116e33a0945115d08ced77e603c5bb46e72c0",
-    "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "77e5cf7b344e590b9a15b2c160473f7c212304f624ed9aea8c7a8fd5e0fd787c",
-    "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "2a70ffd7f8f3289e005c0f72e2c127a44f8f014628df7ac01b4b0ae2fc61a9c9",
-    "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "97e2ae0072d5ae01644eda9a0c3438e78da27bb2f78d843fd626d3db36a6090b",
-    "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "7a30075e86bbd33241120dcf078b31ca9ec1877788db2c5700f4752cd447b587",
-    "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "2c1dfbc1361f030a3a116936f3e43e2c3adae2529feffc98a76e78fdad3572d9",
-    "dist/2023-01-25/rust-std-beta-armv7a-none-eabi.tar.gz": "aafe7ae2fc49e2c4ae9e1e008700f399f397dfca05d624dac4999f6c733ae2cb",
-    "dist/2023-01-25/rust-std-beta-armv7a-none-eabi.tar.xz": "d4bde0e0db35cb07134f6a94eee24e4359478dec9054e8a3802440eed68f60b7",
-    "dist/2023-01-25/rust-std-beta-armv7r-none-eabi.tar.gz": "fe83fe1f0b051838767589ecc9c17915441a44cd77226c9be26e9a63951bce2c",
-    "dist/2023-01-25/rust-std-beta-armv7r-none-eabi.tar.xz": "94eee8d1125537ebe1002c424c686c50996c03ed31d0a1275d49fd7ef0420ae1",
-    "dist/2023-01-25/rust-std-beta-armv7r-none-eabihf.tar.gz": "6ea9fca06fdb82026505c85a7bf7ad8be01926096be63c6cf20c5625c42df7dd",
-    "dist/2023-01-25/rust-std-beta-armv7r-none-eabihf.tar.xz": "70459483493bbb4cb2cc4b2af0cb012c01c47afc214643a588cf894a028a0ceb",
-    "dist/2023-01-25/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "27d86df76c05de73d0ff9542d6904f03ecbd2cedd3a9d6a9cb654dcb78363514",
-    "dist/2023-01-25/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "24b5a81721fe20849bdf075d39a99c0e80a21178327f9fa96b21649c99486213",
-    "dist/2023-01-25/rust-std-beta-i586-pc-windows-msvc.tar.gz": "3740517ab4573f77d5812c9b9c04fe63eacd29e56ea7ba5c5f335ad66026bd30",
-    "dist/2023-01-25/rust-std-beta-i586-pc-windows-msvc.tar.xz": "6c4e780249dcf8b306f8fab3fddd232724248b2670113dfc14c7823781d669f5",
-    "dist/2023-01-25/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "15fc95314219ac5b38f44a4ec3568fbb4ce66d7ff7b63cdf1fb7a8b058f2933c",
-    "dist/2023-01-25/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "b1a5ffd05afd400760002da124a8e5c86d091db574bf1ccf255d86b2515789e8",
-    "dist/2023-01-25/rust-std-beta-i586-unknown-linux-musl.tar.gz": "ef3551edc72cb79e776c7792346352eb858f3e3f7ee1c261b47ef974e52d9a2f",
-    "dist/2023-01-25/rust-std-beta-i586-unknown-linux-musl.tar.xz": "0e1a8e0ababab458af0a329e14398274fa55bf0e6ce2b2a0a515e5f6d12d6f34",
-    "dist/2023-01-25/rust-std-beta-i686-linux-android.tar.gz": "74a26b7fee3e0b95f4f0e065bcac58b865abd5f9abe14e42b2263bb0b87aee69",
-    "dist/2023-01-25/rust-std-beta-i686-linux-android.tar.xz": "c7df97d2322f5f331d349e35091ab5a61fae8dfc16781f1a74849c7c1e150293",
-    "dist/2023-01-25/rust-std-beta-i686-pc-windows-gnu.tar.gz": "396ca6747252adc4e6d41764df00418de22c22ee77823836c4fa3f1bd7cae869",
-    "dist/2023-01-25/rust-std-beta-i686-pc-windows-gnu.tar.xz": "4536de17560a21d543f81f6bdb25581a3b145b792531590a6ba35464e95c6389",
-    "dist/2023-01-25/rust-std-beta-i686-pc-windows-msvc.tar.gz": "da11b2338bacffa3940497b20fbb2544c0846696925d59cf9d7cf4514dedbb81",
-    "dist/2023-01-25/rust-std-beta-i686-pc-windows-msvc.tar.xz": "5bd5cd665f9e3d92f26998694c12b1f0e53df8ca9ef305c4cc48dd81bbe181f8",
-    "dist/2023-01-25/rust-std-beta-i686-unknown-freebsd.tar.gz": "b1553f92e0d0891717635136ad698a017c6aaab07a58183284752ff5480b37bf",
-    "dist/2023-01-25/rust-std-beta-i686-unknown-freebsd.tar.xz": "d6d2a550d36028e5adf62b875fccbae2f78546828de880e5bea33effca22edbd",
-    "dist/2023-01-25/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "3d9f9c3108d45f95ebd12c284147111155cd3714caa555548111fb6791c7ef1b",
-    "dist/2023-01-25/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "a4d9ee2238037d3ca5d4a9dd51c04737ecc2a12dc0be1e2996bbe46d7c1cebb9",
-    "dist/2023-01-25/rust-std-beta-i686-unknown-linux-musl.tar.gz": "9380bbf6ac2d745d1b7c3207c2cdacdd7bef0ff225e3ee5f22e46d826835b17a",
-    "dist/2023-01-25/rust-std-beta-i686-unknown-linux-musl.tar.xz": "517232f4e831f5305e836cc0666adef721c1b68fae80617a57bfb56405e343b9",
-    "dist/2023-01-25/rust-std-beta-i686-unknown-uefi.tar.gz": "1e6bfe0d160e3650a1a453de57f51673a6e04f9348f361fe08d2e96fa89d058c",
-    "dist/2023-01-25/rust-std-beta-i686-unknown-uefi.tar.xz": "f19c1458ef1386540cffca6cf7485ad22c38f0e9ee8a62e26a4e10eeeddb2a36",
-    "dist/2023-01-25/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "6169b653843ce79f799a99fc7f147bf8315688214dc47a64aed792f5ca274ffa",
-    "dist/2023-01-25/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "7f5e0f0e02c51dd88b9b819d1ae370e922eacf2523dd0ae664cbd8d79b7cdffe",
-    "dist/2023-01-25/rust-std-beta-mips-unknown-linux-musl.tar.gz": "124c50ad3ca4da2c97a5e96599762d7fad6701d0193b4a1ba3249c3a67d349ab",
-    "dist/2023-01-25/rust-std-beta-mips-unknown-linux-musl.tar.xz": "0a07005e369def1cbc8d49cd2904a1fd60c23771eca700e9b4abc49d2edf74a6",
-    "dist/2023-01-25/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "5278c6eab22d49d033595f8b98cccfcb89fa8827ef3a8ce487e78c9f74452d2b",
-    "dist/2023-01-25/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "206a55c0e4fb54ccfe2f372888bf42212352d56a7f1b3ba6628aec130b325573",
-    "dist/2023-01-25/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "f64069192d200f852e82735e239cb678fae027a7120e9d79c136aa4a3887bdb1",
-    "dist/2023-01-25/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "b31af554724c4582494548efda53dbef35db5cd3609104550ab2eee1bcb3f327",
-    "dist/2023-01-25/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "8445183d07e397b5bcd0f45fbb1b58ff22dc0901d0a1a3637761929f6b0e0364",
-    "dist/2023-01-25/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "5919f229d0ca138205def6752109056c989493c3a2a241cbd891bfdd84f8c7f0",
-    "dist/2023-01-25/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "c72e51c7b1a5720dd74a923fc2ce1caaff1da484c063b50f96bcf84db529326f",
-    "dist/2023-01-25/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "9a11cb1d587e2389531edff732c205a653e43bc62132cf697cb9fd04842558df",
-    "dist/2023-01-25/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "682fe8fe1e3dad08190e8c42fb2df8fc734a42df081c59d0b30f4cc9f5fcef8d",
-    "dist/2023-01-25/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "7eee1fff997cd847aac8d6c61cad4bc572d3069dbe59ce2a06c39d6b63346d34",
-    "dist/2023-01-25/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "0b5c68bb95668394dda1c910cf99835007271b5598d4652c7c6b974c6c0b2acd",
-    "dist/2023-01-25/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "411c8552901b80720a3bca0707eef475a7ad1650d34cda0b29fedfa9fc9b1852",
-    "dist/2023-01-25/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "187fef84302125e38937cf390bdf26d40ef98c6d06fd5893db8adceab3e75f04",
-    "dist/2023-01-25/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "83ce613db91a23549e4a1e1d5e4c24ad3ca7ddfb586b45d25e2bd85e67a19390",
-    "dist/2023-01-25/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "785bdd67b22af15637696a03b6a4a917f8195049a4bda14a88dc48e6c3101a5e",
-    "dist/2023-01-25/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "df034c1d2baea51f6756e1efef58db81cda5e795691c3a7175cb3b61edd8f33a",
-    "dist/2023-01-25/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "24d020c96db72a49c39dca1546a683d4d2134718dafbd74fb846dc77b30cf78e",
-    "dist/2023-01-25/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "a798a58bf5723f86b08a11c92f901cee246c5a0af06c4f7e08b303c7fd6c0354",
-    "dist/2023-01-25/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0c383e01f53b5bf85301c46978493e94aef2eba98a966ea283771de7829ea492",
-    "dist/2023-01-25/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "61040426e2eb9950a3487109977ebfe66c134f5394c95847df222ff24c61563b",
-    "dist/2023-01-25/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "ef44851d420b5ee0cc3351084c9bc645e4caba447c8dd737840315687547657d",
-    "dist/2023-01-25/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "5cb083baabc7f33c515f2dbdaafd49465c85888d97af68dbd2bcd08a3e70e016",
-    "dist/2023-01-25/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "96bd2d16b470e6377c9c2894b24e77d9f7b51dd54d5369dc361791153a9d1519",
-    "dist/2023-01-25/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "93af94b167327c431158be466ff47b3aab8a77319bf7bed8bdbdedb4633a8e67",
-    "dist/2023-01-25/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "57071d1f70a444a1b4b26b2a579e6c6324522893de60be9e97fe281e8878f276",
-    "dist/2023-01-25/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "a75b8cbf062d1c6fcd8b2089c83f82b75247ced44793272ec56849c4448389f9",
-    "dist/2023-01-25/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "195fe88c1b4b77cb12f566e27a9d3ff25ed2edf5f26be9b3b3dd0a88ac6f5e3c",
-    "dist/2023-01-25/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "76884a90032874b98b0f4f873818dd90befc91d2ed96945120a1ce5a6a80c4e6",
-    "dist/2023-01-25/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "017a6896b2b0e534c1c80f13eca4a3a570560800a117ea2d6b4ae0e6d665a969",
-    "dist/2023-01-25/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "ac712a5b5cf3cd2eb2ae3825e75a5d84c5a899f86a104195b200711da15e9e53",
-    "dist/2023-01-25/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "405fd311dec82db95adea38b3ec0e53454aca72bafd58f7960f8be25b50f9bc6",
-    "dist/2023-01-25/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "0a3c8988561da39a817a3dba8115237f1c4ab6642f1925f52b7398102184ec7a",
-    "dist/2023-01-25/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "65b8a84d7355f889de036b1ce760068c2b81d73b43e5f7da29f9706ae1806a89",
-    "dist/2023-01-25/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "1c8843868742c36a5e9f6839275b4ad2b8a45f587f18f798448a674e0b0841cd",
-    "dist/2023-01-25/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "b225da38b37554abb5a7f098be013b2e5971f9f34c634661d3244dad3ef1315f",
-    "dist/2023-01-25/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "78018c4b996f7fd8bcaaf6073c84a3180250840263b54cc68ff6d195855b0727",
-    "dist/2023-01-25/rust-std-beta-sparcv9-sun-solaris.tar.gz": "468853e0d54a486aa0a25dd9fd2ab47c08e48c6aa47838c350c108738d7ca812",
-    "dist/2023-01-25/rust-std-beta-sparcv9-sun-solaris.tar.xz": "c59fec4162cbd9204d73f7aada19aa459e23f3ed73584203d83d52439a982382",
-    "dist/2023-01-25/rust-std-beta-thumbv6m-none-eabi.tar.gz": "326a3fe4191366ad170f44bfe726d80954024b1a3c7560d75da77bd16b44cafb",
-    "dist/2023-01-25/rust-std-beta-thumbv6m-none-eabi.tar.xz": "9c59dca2473fc377b65ce74cda0a3a064cf9fe07b1fb1eca0a4641b6de397d0a",
-    "dist/2023-01-25/rust-std-beta-thumbv7em-none-eabi.tar.gz": "ba2a8bd5d55ee9eefb6f5a5bae987822bf763783ac0374b97c823cfbcced622f",
-    "dist/2023-01-25/rust-std-beta-thumbv7em-none-eabi.tar.xz": "e8b7df90ffd190d0122d20d4c070f42273bab2da67745f831934fbc09730f34f",
-    "dist/2023-01-25/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "183f0945d1df7a68c45bed842991486ffee21a03313e60e89746ac4122ca348e",
-    "dist/2023-01-25/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "039816d5dc555e28fe45183a09a77a6357ce571111041740d0f95e89489b7cf6",
-    "dist/2023-01-25/rust-std-beta-thumbv7m-none-eabi.tar.gz": "22c48ee80a14149c2635eb344f74ec5765bcc5b7eb0fa1c7ad55b25c016c0934",
-    "dist/2023-01-25/rust-std-beta-thumbv7m-none-eabi.tar.xz": "a690f9227a3587f5dc143ab86a1ea7c83777a36b1ff18e877801c73745ff80cf",
-    "dist/2023-01-25/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "16978fed1307ce642c4c9b0acfb09d9dc532b64a72d25e2d1f3ab3afbcb673b9",
-    "dist/2023-01-25/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "c1cb59f61a45cb2a842d235762d244a4f4b2f078bc9cd1fe6ef5c632c665573d",
-    "dist/2023-01-25/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "7d005cc7f199344bf7ecbcb5d3a4acc8ef42cb61d18fa091fe001872a69ab4bf",
-    "dist/2023-01-25/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "cb567b761f1d78188538e1a5cf4f01aadd641dfec3e8c1a3e2ff2d5e7b930070",
-    "dist/2023-01-25/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "c7c83022f3772e1f7af9e8883a1082695f17956ad4b2d4b8fafeb2a8b9ec6ee7",
-    "dist/2023-01-25/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "392e9bdc0d84e9b9ab83f7118abd07ca39df9fb5a8482f6c9a1bb8969db2c1b5",
-    "dist/2023-01-25/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "97f59b364d4a3491f612217f455b1e7285691e12e73e42d4e7a074c301a973f6",
-    "dist/2023-01-25/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "4935afc5e64589ca8f06d3b8bda2ccb89901a60334b50c45be0b760d6f9f58a8",
-    "dist/2023-01-25/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "eb165b5f5924a077c563d7e8e2eef96eff9398432748070b87f4baf0d04388a3",
-    "dist/2023-01-25/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "9c2bf943142fb554fe2332cd7d12ebd568b8b59e06df73e45ad35da27400757e",
-    "dist/2023-01-25/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "bbd4bb99dbf9b8a178ae767962877bbe8dbd73175e68db654d7eb208c0f10cff",
-    "dist/2023-01-25/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "265ef776729a591e3867947eb23384aeaf02887a2f03f893bb21489bac1aff88",
-    "dist/2023-01-25/rust-std-beta-wasm32-unknown-unknown.tar.gz": "177edb18d11154664c510f27fc02b566c40320b5604587975b0897a70647be3d",
-    "dist/2023-01-25/rust-std-beta-wasm32-unknown-unknown.tar.xz": "7105e29d9a6540ec629a8844407b84624efed5e2a2642a5fc18fa8d73ad5356e",
-    "dist/2023-01-25/rust-std-beta-wasm32-wasi.tar.gz": "d13a3c25523c269b2515d254558af46bb35fe24d796bdd00aafcc84c63f3ac69",
-    "dist/2023-01-25/rust-std-beta-wasm32-wasi.tar.xz": "97ee2ec6214ffc91e46e4e590acc8dc4e69a7a935a64a0e2af31940d745e2ac1",
-    "dist/2023-01-25/rust-std-beta-x86_64-apple-darwin.tar.gz": "d184abb149484d78b713cd1d0f94db958dc4ac182eed453178f669c44856c823",
-    "dist/2023-01-25/rust-std-beta-x86_64-apple-darwin.tar.xz": "e3c448e63d87842f42f99390d7d0ed18c13e03a226967e8f2e9ef8c764d10318",
-    "dist/2023-01-25/rust-std-beta-x86_64-apple-ios.tar.gz": "04c884f5f4c4a6d1dfb0941b62e16ec5516d42e6ecdb7b3b86f23994b8c7b295",
-    "dist/2023-01-25/rust-std-beta-x86_64-apple-ios.tar.xz": "6a3c0e72376a2f1654e7ac08dc5e38794a91b432450c7bf978be97ed10f1fa61",
-    "dist/2023-01-25/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "fc41a378f93c5bf1280c52d21f495924c2e76925f609356b8d27e43d0650d2ab",
-    "dist/2023-01-25/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "ab6bd497938262cae110bf9f39cc94f5ef1ba831db19e63b4d60c8fef7f8dc90",
-    "dist/2023-01-25/rust-std-beta-x86_64-linux-android.tar.gz": "d990e089f838d0158fa2ba3ea08153edb48f4346e682f0fdcdfed1b37a186b2d",
-    "dist/2023-01-25/rust-std-beta-x86_64-linux-android.tar.xz": "0b6e71cdcef8c32e649dc209dbe9bc30a0864aba4fc85d0d615ff5c405204f6b",
-    "dist/2023-01-25/rust-std-beta-x86_64-pc-solaris.tar.gz": "3cc30012778b45a27dc6c92f5cb0955461dbd1aba130c191c20a510d29bf2c00",
-    "dist/2023-01-25/rust-std-beta-x86_64-pc-solaris.tar.xz": "0e3f033b01d1223d9f55c86497c9625c4de36953b6c269ca622c96b2fce09afe",
-    "dist/2023-01-25/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "18a61cd3593bc67eeb93b615c4585e18495128cd4f50933776705c6ff5cf1616",
-    "dist/2023-01-25/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "8bf3998dfd69a17354dd79dea20220f405a2a116842d3813fe033cfa5a6aafdb",
-    "dist/2023-01-25/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "76137f8246ad53adaf26d739c91dd3bc5820697a0c1d2af0937328bb5e6536b9",
-    "dist/2023-01-25/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "2febd8119b376da8f2b1baf3ca63b97d11a17e1a766986ff1d6dffc522cb0081",
-    "dist/2023-01-25/rust-std-beta-x86_64-sun-solaris.tar.gz": "b5769729f089ea5cd5fb5ba1995a0e18dcef21425b69b7e952d42c5bdf0253c2",
-    "dist/2023-01-25/rust-std-beta-x86_64-sun-solaris.tar.xz": "a8593120f87887738390e0ec9ff1d72a743a77dc17a33276e7bec7b04f45442e",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "269fec46599b8839f3a81c6cc85fbca7a7e86cb661e5cbcbffb853ba674ae1cb",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "20c2d1d3e64f56f00c237ae261d5880a7fd7c6f1e2360dc7fa0039b3ea932c66",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-fuchsia.tar.gz": "d64735ce43c75d7c741f9cb7754812f09e21706be8bd0931d72b09916d312844",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-fuchsia.tar.xz": "f501f199bfe1120901e919a14684e57f0723b59ffb5cad79f501834a63df5570",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-illumos.tar.gz": "a80058880e7441e2cd6bb77a7a284902d15dc21d8f0b37f2af3b3da31f07f9f4",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-illumos.tar.xz": "17d07564595b2dbc9eecc8271d3332bef81c7a57138559740c606d2181777f89",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "0e4c01e6438fc005ba7177d33cc0dba8646eb51a47da06b079ef9fc2e264f052",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "1f95934a853b0ce1f4bc50ac86b1ae74a34acbae8a64903faf6f7ba63e49051b",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "431fa66d45ff345f1fb2e279eb52ab24757ed3971f049f9a04a63b228a417f59",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "6901b028b8df3d09e994387a810d3a74b873d2ff5fcf93c1d49bf7c3521a506b",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "a22d8f960e3d15886f893dd4e137becf9c84b1bb2ce500d574e5cc85f43b2b64",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "1fa467a1334a1cea4af8b27f7fc186eabf3a8f26091ae29b501bec6b2564b98e",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "50f2c04d4ee499959f52546af600c40b16a5627bb9adddeab819519231cf1efe",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "69084f5bf6e22d6ba232d2040bfee15b00418ab20980c716602a19134ee54bcd",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-none.tar.gz": "5a8b98fce343e17fdfd2f3f9b4f810097cdf12430e02d65b3d1042e273f1ddae",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-none.tar.xz": "d5db956978faa532d822609d475599c12507e5b67ac73b9a9194afb7449b9b7d",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-redox.tar.gz": "3c4f69556a6ed2c64fd6274bfa17ff489b5e0c9f1f8d6884fe31c28c39e15d89",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-redox.tar.xz": "feb6456b55a38b83755b281e039941d97659947b289ac2750fd3b3588cf43fd3",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-uefi.tar.gz": "81e795c668369a3947d4d69aeb4f823c8446b09ae18c6fdc800d54aae514f27e",
-    "dist/2023-01-25/rust-std-beta-x86_64-unknown-uefi.tar.xz": "5c51b99639e5f67e01fe37a868dae17da4ff11d755434b189cc4ae81453826ac",
-    "dist/2023-01-25/rustc-beta-aarch64-apple-darwin.tar.gz": "9d6277d58b9a679d47eb80d1132d590102f632d5fdb85ba54ef653b2e602c6d3",
-    "dist/2023-01-25/rustc-beta-aarch64-apple-darwin.tar.xz": "6a49fa544dd3bc4d657ae064863b760935977674e6c837f6a7f84dc1c9dbe95a",
-    "dist/2023-01-25/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "0536b525d92007041a4d5f4b57601bcc17e1257f44eddd1e4630fbda8b5ea2e8",
-    "dist/2023-01-25/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "35621c50a8e1ce5591dfdf95b4f5e17e60478309348e67f6e3bf767b57c494ba",
-    "dist/2023-01-25/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "feb0c0534f2f78500a25906fb6f0bd5772574fbfbd23b6abea807f074905905a",
-    "dist/2023-01-25/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "fb269a472ef44aad092259352bb55b24dafc56459eacb7300fd7db0bbc5a96c1",
-    "dist/2023-01-25/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "98514e08e1a21f94028df39496e802f5b6379414dad4e7069253cd8b3f961c43",
-    "dist/2023-01-25/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "b01b5ef23232834174ea31bbf402fd4652769a7fac5b522ac28e53c469389b60",
-    "dist/2023-01-25/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "d638873a2fe3bb666174b4270a44da25a9f7f05f0a2544598556485661b51d66",
-    "dist/2023-01-25/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "7bd32b738a280b6d42fb925b5c7cd8b4ca660285ae77cf27b0ed6eafb0b0237c",
-    "dist/2023-01-25/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "8ed861c6ccc085030bb0947119746df3c83b9971e7b7c0ca43a8133700f985bc",
-    "dist/2023-01-25/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "f4ffb8ec45475b96815eccb657d9a5f443e8067a2f7b50a18eaf80c8a9cd1944",
-    "dist/2023-01-25/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "e6a809e4e255e265aa54ac730655569e93b0227037e5eebe2995e6ed13c4a2fd",
-    "dist/2023-01-25/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "0849a22e9d82c3cacfb39c5067106767bc40380e231842e968770b7d79dc9376",
-    "dist/2023-01-25/rustc-beta-i686-pc-windows-gnu.tar.gz": "348a94bb0048a2de0764ea5ebc83a6578d1f63f4edf8d6627cd346345cb3beda",
-    "dist/2023-01-25/rustc-beta-i686-pc-windows-gnu.tar.xz": "02885355eefef4a901522a441c376a59521ff91889dd6e2438cfe5869360ad7f",
-    "dist/2023-01-25/rustc-beta-i686-pc-windows-msvc.tar.gz": "56d6b9b2d0e8eb13a568b60f2b5284cbdb3efcbc921d6c318408c58d12c6ee11",
-    "dist/2023-01-25/rustc-beta-i686-pc-windows-msvc.tar.xz": "bcf405c76b2aebb76ca70595ddbe5de1faf8c34320b08cd4839db7f46dc9dc7c",
-    "dist/2023-01-25/rustc-beta-i686-unknown-linux-gnu.tar.gz": "6b5c11f41bdb8a7b596ac92bfe18e7a2410a7fc77fe7ca7036e72c563b9e41c0",
-    "dist/2023-01-25/rustc-beta-i686-unknown-linux-gnu.tar.xz": "7291ffdbce495b5d0ca017730495300a72d3341170d099b3c8abda5cb9ed190c",
-    "dist/2023-01-25/rustc-beta-mips-unknown-linux-gnu.tar.gz": "6005076b8cd38020a02cd2720e8c67491d31f50465d62d9f5148d93feb4eb198",
-    "dist/2023-01-25/rustc-beta-mips-unknown-linux-gnu.tar.xz": "1b421c2addb488faefec78cdcbbaf03a9c45640f4ba6740bbb1afbece3e30ba0",
-    "dist/2023-01-25/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "2d1f7463d3922238c189c5f669b8f4e80f85f389f5edca000b63ebf041fb4222",
-    "dist/2023-01-25/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "29dcad8e598e6b79730a53146d3d8ceb5acd0029a83216060ece931d149e9a97",
-    "dist/2023-01-25/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "c3e1527a463155bc9ed2c3eb65217c72fd067bbd316432a16a2777a444e7eb9a",
-    "dist/2023-01-25/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "8a031c5830bb8168c1e20426082c0783fa52310b22a28c5fbb5b1214adcf3bd5",
-    "dist/2023-01-25/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "5c1af72641cb7bf514f936def835ebccfa908434f9e26e6d3cf65756d68fe24d",
-    "dist/2023-01-25/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "40a95925bb98eadd7b49be71dd9fa76abf09fc16bd2d6707e3206cf7e7f9b9ce",
-    "dist/2023-01-25/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "2dfea875b3b5f3405f9df83fd5a5144b8fc93a90ba17a3ffcb437c934a9772e8",
-    "dist/2023-01-25/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "2c23590890472f2ed15df449a33188bbc7d3dc8755e8929861ccdfeb24ee0909",
-    "dist/2023-01-25/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "0b31cad32717c5c7a75069bfaa32fab82d0eb75190b0d34d2e09c221def5f7a5",
-    "dist/2023-01-25/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "939feb641d84aa98e46934c3896adee94169d8e5d8d2d97065e904aa1eac16ad",
-    "dist/2023-01-25/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "d031874dccc1fc029196bc49f7713805226be2ac03a17fc38dc2f40c7f807093",
-    "dist/2023-01-25/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "8b6f367822b14dfd341d711c4736e00ac1fcc914a3c5214209742f2543bba880",
-    "dist/2023-01-25/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "6fb98f6c504ff7278af6f840e39d1236b7209a35a3f5dc78d281c59a2264b525",
-    "dist/2023-01-25/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "1e5a16e7c67bad200e3f051aa959cd9123ad26e15443128ee9ce28151b28e7ba",
-    "dist/2023-01-25/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "c8bbed9a7319e601e9e53461665201f89aceca9bc72dcdd1e3206110d535c6c4",
-    "dist/2023-01-25/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "05af8b1637b522af7ac981d133eaf88c157a7d4ed414ce53c13bbca0667510dd",
-    "dist/2023-01-25/rustc-beta-x86_64-apple-darwin.tar.gz": "ead6472d2644ffeb7f27252e0445aa27b9cb028dc982da011069975767711249",
-    "dist/2023-01-25/rustc-beta-x86_64-apple-darwin.tar.xz": "3777d00c129c51b8980afc2ba1b1605f58490ec4d5203609d260e05ae5801182",
-    "dist/2023-01-25/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "5871e7fa9b9af9af9ccc405866774db110dc5ba8b66649c87f546139c383cea1",
-    "dist/2023-01-25/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "9804f9a57acfa97db3a33fa7f77f5a8ced7d6b9e5013e61aa76287dfe45d9223",
-    "dist/2023-01-25/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "3a7387c88e4a17e331d8f8800e6be0cf113242edb2b760fcff0dcd2ff97c1ca8",
-    "dist/2023-01-25/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "12becb176b75b9274a44ccb22a4859fb8cb52df2cf954011c7294d22dc2e8721",
-    "dist/2023-01-25/rustc-beta-x86_64-unknown-freebsd.tar.gz": "262df9ec15e8b14d1a2959f9d386717147af17612ae92762916e9e195ac83c7f",
-    "dist/2023-01-25/rustc-beta-x86_64-unknown-freebsd.tar.xz": "2647f9420cc4b2a2a94b32ef6c7d88285bb50c3b04bbd29bdc11f6e5fb8f9c4f",
-    "dist/2023-01-25/rustc-beta-x86_64-unknown-illumos.tar.gz": "82875b6f60bbdea438f0da1a162c30d236fdd32124296a83510954f89dfbb20d",
-    "dist/2023-01-25/rustc-beta-x86_64-unknown-illumos.tar.xz": "19bd296d5c116bdb620e50b6fba3c7d5a5e978f26a8f1be1afec1c6854408d2c",
-    "dist/2023-01-25/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "45b8d74f203b66d25a15e59db755918d0954a3338f08236664007de2478e2438",
-    "dist/2023-01-25/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "c047becdba71a802c1d06b31e5c3dce8efb11a9daa299e1cd03a0f9f6b48cbf9",
-    "dist/2023-01-25/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "a649445f1676acafc59b4808211aa669c9fb8093cabb7007432d0ae2f6e21239",
-    "dist/2023-01-25/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "b6ed06a8df0de6b64099fba4d1ca9478e0802dfc086308f425692ee40faa8d2a",
-    "dist/2023-01-25/rustc-beta-x86_64-unknown-netbsd.tar.gz": "d939bd071f42aa7657297110be68dd9d2aad840272bf881a1fdc82053914f970",
-    "dist/2023-01-25/rustc-beta-x86_64-unknown-netbsd.tar.xz": "5671084575291d8c4ef2ed0930b22815d6810e2378fb98ca5a0738faa76b525b",
-    "dist/2023-01-30/rustc-nightly-aarch64-apple-darwin.tar.gz": "f634a282a8388aff57d988616f17f2c511253a02d45193b03fa87167448a8cd9",
-    "dist/2023-01-30/rustc-nightly-aarch64-apple-darwin.tar.xz": "4fd6a4ec8665ba71ccf3ac7d08f9010b4e130ce496bc62548d36170786f213ab",
-    "dist/2023-01-30/rustc-nightly-aarch64-pc-windows-msvc.tar.gz": "5b7fc325745b2f1e22b1a58ead8163314c3ec06f4a30483bf7ddfb57f811a2d4",
-    "dist/2023-01-30/rustc-nightly-aarch64-pc-windows-msvc.tar.xz": "4aa8d587ebd53bbd11c33f263991328576977d801d5b6eccf56147301ea0f52e",
-    "dist/2023-01-30/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz": "7838bf7da92539b0329be0b9b80f0738df3617e982f539326a6a99892eb905f1",
-    "dist/2023-01-30/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "636af094f94de9baa3edd5f9e1b7655e0bb7f6f23d24d6f389a3abeab7360e00",
-    "dist/2023-01-30/rustc-nightly-aarch64-unknown-linux-musl.tar.gz": "51b8a8a06244ee37d2c37e84154ff87132b4f90a1e62a8c9454ed5ea5c296c1f",
-    "dist/2023-01-30/rustc-nightly-aarch64-unknown-linux-musl.tar.xz": "cc18ce5f4f461a830c725ca8ddccda17bd726374198c487810eab8d36a8f7c98",
-    "dist/2023-01-30/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz": "e2d7b96bf5e2feb47019c63067dbb1627bf26ac4e730774d29ea9f6967edae3a",
-    "dist/2023-01-30/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz": "0483f07f1a53949c2f04e2766f53fe9138ce126059f650ac61215e6a84c5fd57",
-    "dist/2023-01-30/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz": "d3ad417041c432438f1ed56a2324ab412dca7631a74da03e0bc72cd28e69f197",
-    "dist/2023-01-30/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz": "f029fafa0635efec9065d76780f003e2c4220c7b6ea4b426ebcb57d943403998",
-    "dist/2023-01-30/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "dd2ee13ccea00c23ca2f90872c7c31a3a1ef008962db9cf8066acc130bca778f",
-    "dist/2023-01-30/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "dc23fa4c0268a7227e0f9e4941376ffc4c64c0614622f442da10dbb75e014dd4",
-    "dist/2023-01-30/rustc-nightly-i686-pc-windows-gnu.tar.gz": "d4b02e59373fe60ba06e979f784bf1b8c94ca4a5ee471ed83814623db9e14af6",
-    "dist/2023-01-30/rustc-nightly-i686-pc-windows-gnu.tar.xz": "5355e1bfdddd2a56dd0c882fc492e4d571e5b29636d381e848102e996ca9b680",
-    "dist/2023-01-30/rustc-nightly-i686-pc-windows-msvc.tar.gz": "02a43fb72394837461770c1b472afb534ac03bac9cf23bfdbba8227cf879dabe",
-    "dist/2023-01-30/rustc-nightly-i686-pc-windows-msvc.tar.xz": "78cbe74bd0f7029b01e3aeb451ea6bbc1656db1fb4a80caac4cc27b6e0144b79",
-    "dist/2023-01-30/rustc-nightly-i686-unknown-linux-gnu.tar.gz": "7fa9a3e3d70a6c15bfd00a0b5a83d73f4e952862b8ef1d6837d3598c4cee8752",
-    "dist/2023-01-30/rustc-nightly-i686-unknown-linux-gnu.tar.xz": "76b3abe5c532785ab80804461204280e6d853773c62956f283f5dc88130e310c",
-    "dist/2023-01-30/rustc-nightly-mips-unknown-linux-gnu.tar.gz": "2aa78ea99fceb90e568f6c46881623f5088afeaf47ba204abf2ef755397e84eb",
-    "dist/2023-01-30/rustc-nightly-mips-unknown-linux-gnu.tar.xz": "6abe1f28662aca904b1fd91e46e0441ba7b4f66f1e7757cab93a0d73012b36fc",
-    "dist/2023-01-30/rustc-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "3afadbbe1b073ee2a81609c87c3d88a5d7344765b970b8c48dcdfe539c5ba540",
-    "dist/2023-01-30/rustc-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "f1eb22696c376dfea266090320e7a941986f8de2176b6ceb6dc0f0452994ae4a",
-    "dist/2023-01-30/rustc-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "c7f548350e118d4281a8a6ac8044c19eb1583683490b0ea6fb9f5f27f5e3873a",
-    "dist/2023-01-30/rustc-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "aad40926a20ac8bda9e534d63e180adfa355e9df22a1068310cf9ae667ffd0ad",
-    "dist/2023-01-30/rustc-nightly-mipsel-unknown-linux-gnu.tar.gz": "4778f49dceea661baaf641531946dda47d8ddb7f801cc63afbec37a86d45a0f4",
-    "dist/2023-01-30/rustc-nightly-mipsel-unknown-linux-gnu.tar.xz": "1ba09bcefaf5ed5a3029230ebc3e9cad33626b38553451b952ef215c68a98e34",
-    "dist/2023-01-30/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz": "6efe1f619ad49c94b3e6fef2a51893cec88ecacf31d963576e6343e8a050d20d",
-    "dist/2023-01-30/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz": "971fdc824861c98bf223fb2c733e780cf87c90f3a5646561f4e35fa8cd068c7c",
-    "dist/2023-01-30/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz": "10741ef62e00541a85747db16f830c71ffa1dce036a95bc43df433e450f96602",
-    "dist/2023-01-30/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz": "b8bc80ee97c54e428c51f56e30cdd610fb07f41bead0409b089fe56237bb0421",
-    "dist/2023-01-30/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "f8f52abf57943895d34ffe2157f863bbdabaf804969baa2624e38a13648d43de",
-    "dist/2023-01-30/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "7dfb9af100df05b558c873b5440c532d28de44fbf8c7d933c29481eef6693539",
-    "dist/2023-01-30/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "9454d78432ce8ad61f8cfbe448654d8acddda9c596c36c7863631c638aba949f",
-    "dist/2023-01-30/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "c69f1b0062aaf566d6610e6b19335ed002a281aa65b34c1be001a875b85f76d2",
-    "dist/2023-01-30/rustc-nightly-s390x-unknown-linux-gnu.tar.gz": "92184254f00348bfaa7f40f8a07b585eeb6dabc02e4dff3351cb395b354a930a",
-    "dist/2023-01-30/rustc-nightly-s390x-unknown-linux-gnu.tar.xz": "b41eff99cf9b9851ffbf496ba6dc892d5dfd124da68c91db66d6fb77b19370d4",
-    "dist/2023-01-30/rustc-nightly-x86_64-apple-darwin.tar.gz": "8d901d7c2ed293a9e2d2fb8849edee50e6f6e3c5a049fa91cfb13f8f16571b7e",
-    "dist/2023-01-30/rustc-nightly-x86_64-apple-darwin.tar.xz": "d472dc97f3242d243f584efe113f23e62ac1f53677fb3b3cd1749adb65a6635c",
-    "dist/2023-01-30/rustc-nightly-x86_64-pc-windows-gnu.tar.gz": "9259adfb75f90cd43c99f253aaf4b242afe941c4075eabc6bce824c3337b4d2e",
-    "dist/2023-01-30/rustc-nightly-x86_64-pc-windows-gnu.tar.xz": "e42b3e9a462004296e53ed3e71403caff98b3718ff15508d913e0a25ad02ea3d",
-    "dist/2023-01-30/rustc-nightly-x86_64-pc-windows-msvc.tar.gz": "82f615142be1fed6ffd5c9a6f2d1d3fb73ebf32801348cf6279991c0a76b771c",
-    "dist/2023-01-30/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "2a4e2aad343062379334ee1a73b657656e0c03f0490c901806c864ea8a38ebe1",
-    "dist/2023-01-30/rustc-nightly-x86_64-unknown-freebsd.tar.gz": "2a8fa3a6a104bd35de9a83d98786e7acb7614e0b830336adda30e8d1f1cade69",
-    "dist/2023-01-30/rustc-nightly-x86_64-unknown-freebsd.tar.xz": "37327a8b756918c25cb799f2e5742a07145e4c1e424442a5d975e99aff1f303d",
-    "dist/2023-01-30/rustc-nightly-x86_64-unknown-illumos.tar.gz": "8be0295e8b89b6e8f465b0825b0625232c7624cb897efe3e0bf4da222799349c",
-    "dist/2023-01-30/rustc-nightly-x86_64-unknown-illumos.tar.xz": "8e515082490a64d83771131f4fa5fba8b021d205b56149459e2f2da7584407e3",
-    "dist/2023-01-30/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz": "c105e3dabdc7bebebadc6ffa5b6f3f962057948cdac6647cd5adf16d66982701",
-    "dist/2023-01-30/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "09b82ca24ff847e000aed1b2eaca74cdf0f6e533bd6655eaa302281eb7037163",
-    "dist/2023-01-30/rustc-nightly-x86_64-unknown-linux-musl.tar.gz": "e77d81b158b53a94065cd90f68e26dd12d156084b02c53c51172e02c4db58c1c",
-    "dist/2023-01-30/rustc-nightly-x86_64-unknown-linux-musl.tar.xz": "613c7eab1b998aec0673e1781e3ed78c4d038b449d879c11254b1b6d4345e34c",
-    "dist/2023-01-30/rustc-nightly-x86_64-unknown-netbsd.tar.gz": "ac8c53be048049118af9fd9d356dcc69ddfaafcd52020ea93703c94d6167b367",
-    "dist/2023-01-30/rustc-nightly-x86_64-unknown-netbsd.tar.xz": "28b1c8adfffa7863bcd8a46ef407044d06fc16b29f7b6f42072fcbfbdc779e79",
-    "dist/2023-01-30/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "f7e585d9016a012e2cde4d7e0899e52e1c410c53ed9caf6db22d13f6791ffb0f",
-    "dist/2023-01-30/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "bdea28e1700f34dc0a6e57db5f73caf6c8d1671a8356cc51096f8155f58690c8",
-    "dist/2023-01-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "e9988193283871e678a0d0e08cfb5bdab37d43cb0bec0e5f63a12a38c164936b",
-    "dist/2023-01-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "30d1bad2b730589f9d75ca3e2d410d0f9c90707526ed6a66edac92a19eb3716c",
-    "dist/2023-01-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "7c6c93fa25193360e28a90269439b28465b6693b6ce68ff2eb1c4209c36a9d60",
-    "dist/2023-01-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "4c8331d14ab428b922135690b433f97acd37291e1801635252ab5da849d42180",
-    "dist/2023-01-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "0fb5372bf4cc0b6388194021dc7b6a539bd413e89058c05cdc42c1dfe8d92edc",
-    "dist/2023-01-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "0e2452ff037698781157c30c5fd67f552e897feb1d86b7b074c195c70a6a1a3a",
-    "dist/2023-01-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "6c079c2dde918cf2d9f029dfb3a2a9bebba2504dfe97c5fdc0ef79022415b9f0",
-    "dist/2023-01-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "5ab6fa16d7aaca7e6e36caea8e11b916c089dccb511f79b7f69bba667edabc50",
-    "dist/2023-01-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "7b919c9132269fcde24559af58d3d2fee56d93308d731d891f89dcee193bbbdb",
-    "dist/2023-01-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "53d7c7d03b64526e013c11c49519a63f51562f9682039479c377c92529e5e026",
-    "dist/2023-01-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "c19265cc3a85cd296a85b450e2f4e4b5f3646aa70d6c70dfdfe9ef222fd72136",
-    "dist/2023-01-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "66159d87fd85a4534104da3f7f5c0a14403960ff2c836eb72e35bed6a1ebde32",
-    "dist/2023-01-30/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "be84f8558d15dcc802f399f44f0de58e93b28e99cf62e38c0d6e6078a8d73102",
-    "dist/2023-01-30/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "b4e8f18335aa3cba092df29c3aadef79c0b88e00f563604467cb2485e10cced6",
-    "dist/2023-01-30/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "43ce7581f50e05c775b39a6a6d297d6e8c56a40f5a5817ae4d996d319fbe96c1",
-    "dist/2023-01-30/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "2ca2b20996f1a4cbdb619393a3f544ada208caaf381748ee997a70139e52a591",
-    "dist/2023-01-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "229fb281ec100e68445b5a402a3d39a0947475054c4f043d55ab2e33bd3d2a57",
-    "dist/2023-01-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "65326115afcf1c8e07cfcb9ed294a1e5a136b998557cd60b4cb976520f84cfe1",
-    "dist/2023-01-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "337bdf61237c8e47909c3f14b5c8fdf3b8b14f2b265e6da45cd6b4d8180d0afd",
-    "dist/2023-01-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "d683349af8320d6bc9f16021fc8937920d70e99cf668ce64cad962705dd20ea5",
-    "dist/2023-01-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "08a1ae9e61ef097c5d5ce83e5d2bdda62e72d07b4dd21aad286413c619fefa1a",
-    "dist/2023-01-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "cc3f1f86997c5ccf5607c8f873c916d1158da76ff971d75e36ed8e3a87c86924",
-    "dist/2023-01-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "f4b7084fc67cf17b3cf1d36136aa03aa5b6af188d311684b15395f05104181f6",
-    "dist/2023-01-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "2ab645d5117606f2c7e8decbeae1d8855ec7ba53051144ba4783efee2c58d91d",
-    "dist/2023-01-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "cfa8baa60cc59ac2750f799d33b06eb399d330f318783907717a9e360fd7d85f",
-    "dist/2023-01-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "bf24570425c064aaef31788bbabd6c4938c9323eca2dedf2ac9084d125623544",
-    "dist/2023-01-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "f5437d81735fa67ef24c7b561d1c720395f5d8d4ddcfd88364717a7ed9b96a7d",
-    "dist/2023-01-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "8e19c3c95d6445e1ef9b1735191f0d0bc33802bcfa138a9d676d9b266adab17c",
-    "dist/2023-01-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "7fd91c2ef7e26c08854c91969d167d1c97538d7678c6ed7914eb0f67290d8d5d",
-    "dist/2023-01-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "9e8ada358580b396054278972d532ce2044550071036e9da2eab598e2953a03a",
-    "dist/2023-01-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "eec8b1c24ccaea22eed7708e61bd32bac0850d0dff2b06f1a15a95ab86385363",
-    "dist/2023-01-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "215f1f3bdd8f347af5969c66ff7f7cbf39753ae483e75e689ac581f9d35a64df",
-    "dist/2023-01-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "39460814c429b6a57ce72fafa583d04190053f2c2ce995c8bcb0799ecb7f8bd5",
-    "dist/2023-01-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "6bd08db8702f2fcd9f4cd19a1d977962c84856f748552a96b564e5a77cf2fdfc",
-    "dist/2023-01-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "81d6335fa1265cdf99682503cfb236b914fa17d45f967e456ddbeb12bae2dcbf",
-    "dist/2023-01-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "d36b7517efac2c4a34a1055411f779c386c7a566e4eec408dbc8a319f67f5451",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "1a34ec058cb45189c4062ad2a00ab33387a54716f75005d9959cf0691d06ae50",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "a2fdcb7cc9fe7819699f511d52da0e8ed4e55ba42c63e7b1d61512e4e14e5c29",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "95e3f080394d2e4f9916f17c9cf5137d032da847d9ac1c04519b31177fb1618e",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "c306895982f92c24559b18f8ff9e011e8722c3310e5f70010fd04b0d044c49bb",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "36331cd76f8e918b73ebf6d9095efd0a07cc9f084f194f74c881c14fbc6e8a77",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "2e7caa7209e52a9df17254b17f1930afd5ae973826ce3293f29b8b878aa13042",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "dec92f2c27f785f8ae0db18c2e8a9db87e1ae8addb4302f5cbe9f745cd92c4f2",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "a8fef2e56d9d2be9072c17d75e7ac695eb8fc266fc35e1055fbb25757e6db29d",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "9b5f93f00f61def125436332e4b709bdfe74c441995bae49c0d482f24bd9f8f1",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "4f82313dce2e1315bd0d3ebf95f33bbdf7275c59205b0910bbc92d41c47c7c22",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "69efa04956d9bcf177a3bd9ba9541fa681b39416a1b7dd2b18415b72311897b9",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "0c3c33d744ec05e96298d0bdb9890654ab9ce3e9013b9af14c78683560456820",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "cba8b1f086c544d79aa09ac954374f44d5e7d38ad9bbc2f9e84723d0088592e5",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "ce73d1d03b62931d6eb9508b701e9dacc08b98b484af3daa79ae600c4883a9f4",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "87e1018a3ee4f781b3c1b471fcdf80ebd70096ed58b29db00ad97573626294f4",
-    "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "c6896ee319403ebb5c909b13feabc7411e3aa80523ef1bc84c8aae181514c923"
+    "dist/2023-03-07/cargo-beta-aarch64-apple-darwin.tar.gz": "ec2466b2212a7453ae902b85f7b1879fa9d37275f21972aef488e8b4ca04e195",
+    "dist/2023-03-07/cargo-beta-aarch64-apple-darwin.tar.xz": "5eaa63f70f842836dc847059ec188d5c1dbcdaf77116dc08ba6421eb09706c12",
+    "dist/2023-03-07/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "5514aa4051d8c6ff9b7e334a4cbc8b2ad5ad8db0b9853a693ae998888df0070d",
+    "dist/2023-03-07/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "47b4cdc96afb1796e8ddbf4fed4868d08bfc8fe90c5f517f7c4d8539d89ca827",
+    "dist/2023-03-07/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "514ed7e95642daaff551b31af9f6b8e1afd301d4a3197574c4296dd938f7f98d",
+    "dist/2023-03-07/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "0a3f61fc865330e5a9e1f37a59226a6660995ccae8610e742c2ea42a7b8f9b9f",
+    "dist/2023-03-07/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "838c7a9cfdf76e3e2a0e9c2ad37124eb029ea2f0e015640c7c9ca5f45fe1c260",
+    "dist/2023-03-07/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "1ee5a28da6b8f7fc5f98b8214ed2dda28769dc345c9ffc8046ef644f69fd0382",
+    "dist/2023-03-07/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "3ac81e710ff821e206148d998654044d0b3092d929da3a1d3a5ffa2ada00d922",
+    "dist/2023-03-07/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "64891e59a7e8c94011f98849d37a056535966966f753b923ffcf8ceccacfaf03",
+    "dist/2023-03-07/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "fcab9d5fddbe72db02964adf9fcc13e5acc67f0f65bcdd3bc325aa9f0c223acd",
+    "dist/2023-03-07/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "2bfaf117eb512e53c4f01765d198b3647fc0058d7f77721b58cfab5e72b1f7ec",
+    "dist/2023-03-07/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "dd955a4f258603e5cb5c85473fb6bfeace54cbc2345d99dc9d8fa7f984bcd915",
+    "dist/2023-03-07/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "7b19dbf54ff04009209d505a97bf66327a87ad6ac8a9be4aa26be3d38fec52db",
+    "dist/2023-03-07/cargo-beta-i686-pc-windows-gnu.tar.gz": "88e8e79c154a34596740b85030c16a27d62defef5db8eefad0b3d4397e7222af",
+    "dist/2023-03-07/cargo-beta-i686-pc-windows-gnu.tar.xz": "a996fac21b8198632a3bb3746549f6a36bd7c2b12d9820b7af64a5ffe8074df5",
+    "dist/2023-03-07/cargo-beta-i686-pc-windows-msvc.tar.gz": "3b8834bf152ecf2bda797475d7d556746e2a1374c61e4ab2ff81b41bbff3a87f",
+    "dist/2023-03-07/cargo-beta-i686-pc-windows-msvc.tar.xz": "2fee05bf93a16004f4f8fde437918a44874a9495c1e45d954a1098c104249bd2",
+    "dist/2023-03-07/cargo-beta-i686-unknown-linux-gnu.tar.gz": "544ce4096e455c5259c4577feddaf5a6ec34e6a8bec2710e74f8910f60c1da1a",
+    "dist/2023-03-07/cargo-beta-i686-unknown-linux-gnu.tar.xz": "2f39706fa21cb08d8bfe6a32a5a3314742ddf040bb42e844d5b3f8d0d29fd39f",
+    "dist/2023-03-07/cargo-beta-mips-unknown-linux-gnu.tar.gz": "7f60d7a0d60e06fb4530291f1e64956cfc7c92bd034b63d1ebdedbeb9f7bca17",
+    "dist/2023-03-07/cargo-beta-mips-unknown-linux-gnu.tar.xz": "3c6d8de9f254edd01461235f14e89c7b863da84f338e3a842921dc092db4d82a",
+    "dist/2023-03-07/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "2c0ef292ecd4bf27e74323ae5fa7bd6c6395d70f4adc4e6d4228c266fb87be7d",
+    "dist/2023-03-07/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "1886d8e978dddefff73f758e7c1d28964209dc986195cd39bd8d3d34197cde52",
+    "dist/2023-03-07/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "125a9a8a6d57f1694ed5bef51d9d351da3bbf0ff1ac631641cc5046098385536",
+    "dist/2023-03-07/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "851654268ac5ce9d1f3dae9228464bef01771244945653ff7e9f8d7a52761813",
+    "dist/2023-03-07/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "46a3bd35af46f6b59b610bbc596233bb428c2b8387f95d3e308565d57e6ca276",
+    "dist/2023-03-07/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "d941bb502be268962400e78005b30ac4a5975ab012e2cb7fb631b002a7e116ec",
+    "dist/2023-03-07/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "3853bfc5c0734f3f92e0d7cd07583729d3e67f7ec3b496b5349ac690ee3632e5",
+    "dist/2023-03-07/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "17a0c76f33244ca66c942cd6054e343a395d27437d69f166471f0aee8c404a55",
+    "dist/2023-03-07/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "b37f9c476ae9fe802bdb0fc449657c90a567033f4df382befeee1517f53db05a",
+    "dist/2023-03-07/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "b315d765b176f90a5c74c102687ea8b54ea94d5a772ad03741aa3297a5466562",
+    "dist/2023-03-07/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "e84ef7a7b4fb7b504e6a0ae335432430ad9f4db356650c738e0db676ce672321",
+    "dist/2023-03-07/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "3b830e1077a195e2048b621a1ace2c0470135ae5821f83113a16bdd449dc9828",
+    "dist/2023-03-07/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "db373e61134b7f9340b5d8dfa24fb989e3acadb90b4d27008c08715720cfeba5",
+    "dist/2023-03-07/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bb7d046253f1fcf98f8ef9b33820793579a09d201ae1bb5616302bcf7103453f",
+    "dist/2023-03-07/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "495c5d11852010647d15d54352052ca932034d77f3ac3bd9bf605d52c37fb47a",
+    "dist/2023-03-07/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "002d9a037a9de13d0e99f695bbb8f9177e14df2e6309917a7d728023dcaa1640",
+    "dist/2023-03-07/cargo-beta-x86_64-apple-darwin.tar.gz": "9c93e76966a317d2dbb673345c33269b67d6db101114275424a50f5e4c3b7a89",
+    "dist/2023-03-07/cargo-beta-x86_64-apple-darwin.tar.xz": "0ac70e1699e2684fcaff30d4330d04795f3f9579226dc1dd0ecefaed9efa24de",
+    "dist/2023-03-07/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "8ad0af38dac9c0a49d73691d7f62487c8c72a378ff4fbb7f380fd106600ce836",
+    "dist/2023-03-07/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "e1c263909d66c14d5b835d2d8ba9df9d1f54750a85b79c4163483126594f71fc",
+    "dist/2023-03-07/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "684b44e6cb7b2ea6feb8a5f768f138b7c3c3819ba5f146461ffa860e4ba2ee0d",
+    "dist/2023-03-07/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "194037a4e7a035becdf8540532625e7a3d2e5e9a75c093713467d16f2c630fda",
+    "dist/2023-03-07/cargo-beta-x86_64-unknown-freebsd.tar.gz": "b19ed2a67bc6d654520c2ceda0d1a8e0128a0d042a72cb6506eaf975c3665bc1",
+    "dist/2023-03-07/cargo-beta-x86_64-unknown-freebsd.tar.xz": "2773155eb716d1cde85c8ee7fe87f534decf08cb92d4812463a8f5f45b5cf4b9",
+    "dist/2023-03-07/cargo-beta-x86_64-unknown-illumos.tar.gz": "3d97d07c075c7473645b71391fdecb6b8a43af42f15ccce0bc13146624f3d9e7",
+    "dist/2023-03-07/cargo-beta-x86_64-unknown-illumos.tar.xz": "6266332b1a18e851cd4cf618c1ba5a8162c06c8ceffa3a6e619cbfaf5c8f2914",
+    "dist/2023-03-07/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "6e0ca0e10d1243e81768f1760f268aa2ce1dcf4f79a718a44e09b92ae5b2c87a",
+    "dist/2023-03-07/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "84aa0a73dd6d3ab9d5efb10e0480dedb864341124c19b35040239af27fcd8651",
+    "dist/2023-03-07/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "6de4590228b94c6c62fec90da7f5579fef16cddd30d4bad29ac39e40081818be",
+    "dist/2023-03-07/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "317b64417648885b08064543e0dea13d1062e682224b3b866c12ac6abeda1648",
+    "dist/2023-03-07/cargo-beta-x86_64-unknown-netbsd.tar.gz": "aad64656cc4b9915bfe5ac780ac935964a13481a9070ca31f58d5b8c1750e40b",
+    "dist/2023-03-07/cargo-beta-x86_64-unknown-netbsd.tar.xz": "0ba3f47a551b38c83106003c775539b7384c9bbfa4cae28923e63e28a32227da",
+    "dist/2023-03-07/rust-std-beta-aarch64-apple-darwin.tar.gz": "b3f00164840826f89eb930445cac0afa2ebda2153195574b91ff4dcd286042c1",
+    "dist/2023-03-07/rust-std-beta-aarch64-apple-darwin.tar.xz": "c94d3fe8dfaf35f88d557a37e3aa1da8999b5e2e022f85f1bc0ae7ed5218a3ef",
+    "dist/2023-03-07/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "3f43a002c0c099eedf12c2d2d3e1bee3c8ea345368e89cedd5918705f37086d5",
+    "dist/2023-03-07/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "891547f5c2d06ef95f272f829438b0d5c9f34d9e1e7d068dbb0a5d31c685658c",
+    "dist/2023-03-07/rust-std-beta-aarch64-apple-ios.tar.gz": "c1fe0f8fb661dec65dd7a13b038deae93d4b66f0e0988a0a72374e9945915612",
+    "dist/2023-03-07/rust-std-beta-aarch64-apple-ios.tar.xz": "1f65f0ae9685aaf14805b63111ddae27c8e9b39cc88cb3a5347ad9e93d863581",
+    "dist/2023-03-07/rust-std-beta-aarch64-linux-android.tar.gz": "9fc988f57fb6a0530a338cd3a0a87925b095e9a2f3887f87231c9414828241c5",
+    "dist/2023-03-07/rust-std-beta-aarch64-linux-android.tar.xz": "2aab2cc1377391588db019a231d8f989de79342a630625a4e7c2fee560549668",
+    "dist/2023-03-07/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "4527b7439a0419e96b8c59735fbe98d8628985b63ce64c24749273b625012c39",
+    "dist/2023-03-07/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "80badae3069223541e3092b07331eab3330bd66a21522037fece15314085c513",
+    "dist/2023-03-07/rust-std-beta-aarch64-unknown-fuchsia.tar.gz": "6f7141d28b549d6cf6f64a5944a4748db730d865a9bb1f3a344cd19cd45269d1",
+    "dist/2023-03-07/rust-std-beta-aarch64-unknown-fuchsia.tar.xz": "87f97fad69b53a36354c17abfa58edbaaf86d1db071a53fa96e9822c4f0a7846",
+    "dist/2023-03-07/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "8decda618f8cf30f51b8f26861baab0f53824af6cfa965af585f0653771d113a",
+    "dist/2023-03-07/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "dd140223ec842ebe4c69ec6aa2966b97dacdd9ce112490e310f374134188d0c4",
+    "dist/2023-03-07/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "4aa6ad6fbfb9bea40c5b4c3fdae8f79feeaeca71f0848c1e9281650d4b5880e5",
+    "dist/2023-03-07/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "2d62f25f3c16704f2f52b8bf2fb505b5f8e3a3e44ae3971b0a3081fdd5932bc3",
+    "dist/2023-03-07/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "87982e6e6e3865d520fa35994948c7b82c4fc9f698b4e1316e0ab0bbff3d7455",
+    "dist/2023-03-07/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "815a45384be320225b438be952d798ddcbfc223d7629ce8e106499f626c170f7",
+    "dist/2023-03-07/rust-std-beta-aarch64-unknown-none.tar.gz": "041d4a16c7e6ea18f76b119e069630636716c5f7c2f38e0fdfe69062da9cd942",
+    "dist/2023-03-07/rust-std-beta-aarch64-unknown-none.tar.xz": "227e8434ac0f294bdb102d4aad6c6b1425f148f2bf8eac9473f522e4e8851d15",
+    "dist/2023-03-07/rust-std-beta-aarch64-unknown-uefi.tar.gz": "a1f6c1268c3e28e78f43f2a922ff2d260466f4e2888555c122fb490ba28d8f53",
+    "dist/2023-03-07/rust-std-beta-aarch64-unknown-uefi.tar.xz": "68f46477d721677d2faf0091aad1d2f72387bdf1e5590dead06eec51390e9906",
+    "dist/2023-03-07/rust-std-beta-arm-linux-androideabi.tar.gz": "d1bdca54a9807d058a26f2999fc82ae474e6d5f8cb555196f6583130c81bd6ee",
+    "dist/2023-03-07/rust-std-beta-arm-linux-androideabi.tar.xz": "8cc49d1e16181848d73d617914d664b45cc42fc8bf80d3bca7ca69fe1a4fe7ee",
+    "dist/2023-03-07/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "b09c3776268888966d3752dc614e677c821731593ef757ce45fcd6f6b1b28bdf",
+    "dist/2023-03-07/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "7d43314c408514ece5f3ab6929f906bb224336171c3fe41a5b980afedfbeb172",
+    "dist/2023-03-07/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "9493fb7c2cf30e0c986babd8ec41e3c626373d4e62f8558dacd01cfb85dec04a",
+    "dist/2023-03-07/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "9c833f219410f9e6e77451e4af1a355685831dbeaa99006ac814801883a17312",
+    "dist/2023-03-07/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "8e9c3045dbf1fba7e54b8d34bbc3ed8a95b6c984ebee0123690889455d963f87",
+    "dist/2023-03-07/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "54f7f9a2baf29a5fbc41b6624a4ae0f056e10f0dbfffffcd08377dc6888ca85f",
+    "dist/2023-03-07/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "3f214ab1da499c6a64bc5bc54fb9e95becb318b469531e4d9f7b234f5456dcff",
+    "dist/2023-03-07/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "3e4c0742356393a07cbcc6502e1d1f9a3187921c67d4d554bc3c95bb9e4e226f",
+    "dist/2023-03-07/rust-std-beta-armebv7r-none-eabi.tar.gz": "25f7466a419353fd7e4c9a3771df8f0a64e689d3c38f18e297a6a2c670174d9b",
+    "dist/2023-03-07/rust-std-beta-armebv7r-none-eabi.tar.xz": "42c713261708e90fcab6dd2b8d5b2df4387a33c829bc981f502622d5ca352ac4",
+    "dist/2023-03-07/rust-std-beta-armebv7r-none-eabihf.tar.gz": "31b240296f2e72dbeb3facf395486e8f8ac0b0b5f10a389ed4e6dd803821afac",
+    "dist/2023-03-07/rust-std-beta-armebv7r-none-eabihf.tar.xz": "c33a7bb47b94f8d5c716e4d6b43bf17395bbe9611762a01a5763dda4e725c64d",
+    "dist/2023-03-07/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "509cdcdc107051d7cbc8f02874445a9cb2f0dcd3190cfabd68615b8883b8f32e",
+    "dist/2023-03-07/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "01fb58ffd2cb6257f25d290cbd25be8bf216c18ccbfd97a42317d9e442008d4c",
+    "dist/2023-03-07/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "19ada8a7b1178056008f3168dd854994d6dc0fd32facebef915891b5a7fe83ae",
+    "dist/2023-03-07/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "5925328b29a9a54536ea7de55442f4bcacce4b2ec01c69e7c8d5e7f109f5dcab",
+    "dist/2023-03-07/rust-std-beta-armv7-linux-androideabi.tar.gz": "bd569b576ad68f20d0352e5ae9a7ea0008941f879dcf1cd57f14b7eb7fddb95f",
+    "dist/2023-03-07/rust-std-beta-armv7-linux-androideabi.tar.xz": "c483223f7abed0c145b9c94a6630a1d4caf26720cd451cb4b70971f1f907d6cc",
+    "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "84a1ea166b81fe2cc673beac5831ee182a303c5166279af33478a730a1987086",
+    "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "fa04a59350792a59c8b62800002f5f6e013710d96e3e9d3a6787b1c3b668569c",
+    "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "a605160aeef9a5d60bb83376d816112c621f753e4f16907481aeeea27568da77",
+    "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "d6f3e091217d657a259f7392acf26aa7cc2a7692028412bb97cd26cb7f31b34a",
+    "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "ce179ad977098491c2dd27d57d7dc5a71b9b450b07d36c19e55c0cf9961d3888",
+    "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "fdfa1b894ef5d1afe7cf9790de3077632d4fe693464d19ede5d6b377ff09a73d",
+    "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "673dae7f6d71cf984b69e0bf22b8f50a8597d5c6304ac0fc613ad5116c4a8fa7",
+    "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "9bd8bd07be4488f6828ce4b5456bcfe49bd9ae416cbb859c9b1460334ac9f4fa",
+    "dist/2023-03-07/rust-std-beta-armv7a-none-eabi.tar.gz": "b571a28b02107adc227fe02878064f44e5d23bcc91b530f57b4dfa43a4c3ec1c",
+    "dist/2023-03-07/rust-std-beta-armv7a-none-eabi.tar.xz": "854433b082a6bad442c1b9cc9708357b779cbcb84de65f832cfcba06a6088157",
+    "dist/2023-03-07/rust-std-beta-armv7r-none-eabi.tar.gz": "04c1479778038948f30d2fa87a18562939569422fe57e91659f9f0a5e8ca7f5a",
+    "dist/2023-03-07/rust-std-beta-armv7r-none-eabi.tar.xz": "38d52dc26074ebd93e6a61dbb0c934a66f32dd1113cdd9d32e4d5829ce62e188",
+    "dist/2023-03-07/rust-std-beta-armv7r-none-eabihf.tar.gz": "14e4707dc514aec378e1aae2949231ee3bbe216164a794e7e6d233db54f13459",
+    "dist/2023-03-07/rust-std-beta-armv7r-none-eabihf.tar.xz": "c0bf08f5d378955ba15441b5229d1ef202e6d071a243ae7fb34b9f1724fd90cf",
+    "dist/2023-03-07/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "d9468e5a056478482cb9a85a63aba6d1987026275ed0c8ef64fe7a84ee5e35f6",
+    "dist/2023-03-07/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "77262a746f577b0e6f9b6c1aa338f90eeaf8221ad70f5ca93500459c1749f3b3",
+    "dist/2023-03-07/rust-std-beta-i586-pc-windows-msvc.tar.gz": "2c8c95b80e43acb921674d4a9b2986d89dc008e5977a6a05e820adfd385f55ca",
+    "dist/2023-03-07/rust-std-beta-i586-pc-windows-msvc.tar.xz": "9573dbb30fd7a24d4d7e831f51e6c05c76d856d545ce4601f4e91b784c348355",
+    "dist/2023-03-07/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "f1861d5b7875a81a11a98a6cde90fe958d1819517de21e377cd05b58eb5dde27",
+    "dist/2023-03-07/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "f8e816f9ca02c3cc515d07d5b5cecc8c5dcee64b8deb1bc1ab249010664d1cef",
+    "dist/2023-03-07/rust-std-beta-i586-unknown-linux-musl.tar.gz": "614a80336890ab422366caf16c73c26a7982c2369393a40633eb925113e93306",
+    "dist/2023-03-07/rust-std-beta-i586-unknown-linux-musl.tar.xz": "e8dbf05a3964ce39dc4c732c5a4bce60cea1764c151b1ed4333e0da858659050",
+    "dist/2023-03-07/rust-std-beta-i686-linux-android.tar.gz": "34df9ba98cbb7fef8624e921045110d0b4623028a611f5819bc79aef9e611024",
+    "dist/2023-03-07/rust-std-beta-i686-linux-android.tar.xz": "bef0d789d8d66d0eb69970ee23e4cc966f655efde901db13a4fc9d02c875848f",
+    "dist/2023-03-07/rust-std-beta-i686-pc-windows-gnu.tar.gz": "c86ba5a55d449af72a4450566a9152edac5fb43ab03d1385779bb4ab62255f7e",
+    "dist/2023-03-07/rust-std-beta-i686-pc-windows-gnu.tar.xz": "8dfab1eb07c9391be73cdefd892f6d7ca72be99a7fda5528906343108c5b5503",
+    "dist/2023-03-07/rust-std-beta-i686-pc-windows-msvc.tar.gz": "99c56608131dbab4775a35ea16d50149af37ea57ef0c0dd52bec2639dc3bfce6",
+    "dist/2023-03-07/rust-std-beta-i686-pc-windows-msvc.tar.xz": "1983fae15ae3e5480efb1cbd0fd0509e863eecdc456e50899bdc6cfc2da580c1",
+    "dist/2023-03-07/rust-std-beta-i686-unknown-freebsd.tar.gz": "4652d56693b3432446ebeb5b52399b27d95066c0085a24a4ff5b96a2116cef95",
+    "dist/2023-03-07/rust-std-beta-i686-unknown-freebsd.tar.xz": "a89a970a699864eda563170f41210ae3692059f8b141d532172907ca1456e8a4",
+    "dist/2023-03-07/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "0d6b69445aa064ad6c53a26b52011b4533e83c7398a9ff4a10c29bd2c5f1673a",
+    "dist/2023-03-07/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "4cd1770586a92192da3aa4fa8a846412db8377fe04ce5502792c67d8d3bf9278",
+    "dist/2023-03-07/rust-std-beta-i686-unknown-linux-musl.tar.gz": "b7c0385692fb7218dc16e3935b6181beeaea1adb731a5ca2dc876a3fa825dfbd",
+    "dist/2023-03-07/rust-std-beta-i686-unknown-linux-musl.tar.xz": "92c608fd3be1bf98ce343f4b42e187fa1182560bfe10a2c3110037b0600f611c",
+    "dist/2023-03-07/rust-std-beta-i686-unknown-uefi.tar.gz": "97703dfc96fadd27af79faec3b9b14f5e64549870c5451e8ca5023dc97a7253a",
+    "dist/2023-03-07/rust-std-beta-i686-unknown-uefi.tar.xz": "7470fc83530b83ad3bae30e7185ca54811f97629ef64b70d3fc2fb757639abf7",
+    "dist/2023-03-07/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "54f2ff0de486ab6e6ed6dae72d798e1fcd4653b7df1f8d4127eb6a6396572081",
+    "dist/2023-03-07/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "fb3c1a6daec2ae77de369ef6bd93955d67e70b7b2799a286d2332f5b7d46b715",
+    "dist/2023-03-07/rust-std-beta-mips-unknown-linux-musl.tar.gz": "4af2c66e9e2b3d4003a47aa638177b256db683f7945fd4cf02122c144736045d",
+    "dist/2023-03-07/rust-std-beta-mips-unknown-linux-musl.tar.xz": "8f3f4385b4a6fb9f8cbeec20b7f7b794d1374221bcab5c2a5aa59d94acdd6855",
+    "dist/2023-03-07/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "ae14ec5c0ea8629de6b8db2a83a4ceb08be6475a07c89abbd8697f72f9d46427",
+    "dist/2023-03-07/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "e2ddff933278d45c9e2d4e6734babd3b6a1e104325d814c8faecc4a51d197a96",
+    "dist/2023-03-07/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "d67f7fdfbffcdb4daf134209ae62c051959ef5b450ce12f6ff87b5d7f2d69c7f",
+    "dist/2023-03-07/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "f5ecb43d0445a03d4677b3a8997f899938755c877bad2262dd88f1c5b2960c1b",
+    "dist/2023-03-07/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "9a9b36ce50e1167259c43d5dd8669ca26831bf7d2df6162395df6f22b3c3b7cf",
+    "dist/2023-03-07/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "966d074243e8bdbacbe85fbeae546d9d65b3579015abf18a458798f16ad6c940",
+    "dist/2023-03-07/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "a64b67a50418e8ced6333075541a30f7272fe11f11160969c92efad447c94ebe",
+    "dist/2023-03-07/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "f2fee3ae76bb483871b23a4ec1cc22cd89193e087d5389362385d21ddd162392",
+    "dist/2023-03-07/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "f659bb468e1e4a44288953e654808452f1b08bc7acef546b72e0b31fb3552503",
+    "dist/2023-03-07/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "7be5f817c2cca408804be8f0168e60a407d6088b3758688d2e8a79662b26b340",
+    "dist/2023-03-07/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "2c988d57deb6d9f88a6ff4180b41a65bd2a69722b6d3dd7a80ecc3bfc1ebda0b",
+    "dist/2023-03-07/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "8e852cb52c7189a5de0274bc592a720ab1d657f39dd689aea0c11cc8d45b7441",
+    "dist/2023-03-07/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "24db414fdf589e5c686e0c1441b061d82b480a305cf7926d7a54f3ce6bcc48da",
+    "dist/2023-03-07/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "f4a90b86b5cfd448c5b7c1b29b99c0f016d64deeee7bfb98048d8b0215f15174",
+    "dist/2023-03-07/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "9c04535d6ad8a823e94e98e3d8aa300ae7181501dfb9819ddbe072ffefe2df98",
+    "dist/2023-03-07/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "121faf0e67f1fbf609b6f2746c343b2a7fb7efaf0a7129a9d867e8d8c52d5816",
+    "dist/2023-03-07/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "013b5968c15c7257932ea79c8df23dafdc20606a4dd6e7b7f784d56d59831835",
+    "dist/2023-03-07/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "26abe47cc533337847c021c08fcb88ec77152b5a33500ab948fc45c8bdab23ee",
+    "dist/2023-03-07/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "c72d7e9f58640933bbe5dc1cd7b0ba87f5080ed397099d04cacad992a989199a",
+    "dist/2023-03-07/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "4ef96cf7f4ad93c41b69e9f6a48937cdfb307d7ec65ab2f475707680f638848a",
+    "dist/2023-03-07/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "b4d5fabcc593313b41bbe1a4a201d2acd23f07ce249b6414bb5fb940df519d90",
+    "dist/2023-03-07/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "537d209c9ea5a7d7750206612b353d33d54a5c55af45c4e8e4f113c6d561cd5b",
+    "dist/2023-03-07/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "8307dd2783e0ccefb27cd645ab53717c851e91c5c5a2e466bc2ebe00f23afeef",
+    "dist/2023-03-07/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "f2bb8932f9d2a0e51caf64367bb34d1c30456863d3933c766c69be50c0474ff5",
+    "dist/2023-03-07/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "300892f31875cbca564b54124e85fada8af945247c3a31049e6000494f3a633f",
+    "dist/2023-03-07/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "ebeb2d2bdace58faca8f5d8d3e06581c30f18ac7e0e096d03fd4444a7ca9b7b4",
+    "dist/2023-03-07/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "62d9e27a3c321bed86839ce6a492e28aa51b1d70bd1b0ff0d6cf8784ee78c8de",
+    "dist/2023-03-07/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "c876705073fa8735fb3b89453a4cb00c3324d3e8ee570acf3bab21ab0ec0d240",
+    "dist/2023-03-07/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "97751b6d399463e9dbdae41979d0e6405d0faf90ee859d2bb87787a4146420e4",
+    "dist/2023-03-07/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "cde9469f915b2f37537da5a596ab75eeeff64affd5f26619cd59dab06c03b13a",
+    "dist/2023-03-07/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "000796b94967c2285fa240542063743d389595aa64a58a64145ca093ae505222",
+    "dist/2023-03-07/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "3ce3f15333e074060c6fc97f40bc2d41d582744df97c1e4630839a34397e793e",
+    "dist/2023-03-07/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "8a44c200db94509b83ea2bcf3b5ca7b8ff1f3c7aa0c9b7942ee3047b619aa161",
+    "dist/2023-03-07/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "6484f92b2d2793c47f1665d4c0bb93fe64359a3cafb658957bd3ffa33c3753b2",
+    "dist/2023-03-07/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "d60be45093cbbd1269be0dc0e73ccded00a9b72b65fde8c8c5fb72d79cdcdcf9",
+    "dist/2023-03-07/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "8b46c3bb7a74116d8dfa69fa46cc70b4771c6a28d73c501bc935573e1d06cd20",
+    "dist/2023-03-07/rust-std-beta-sparcv9-sun-solaris.tar.gz": "5caf2b9c9dd509ef50840484b577b6ddac2cda32519b75a97053de85340439df",
+    "dist/2023-03-07/rust-std-beta-sparcv9-sun-solaris.tar.xz": "bc00a55394520283826011467d9f27c74369d47e3d5bd0f9c7b7cc2f2cf74cac",
+    "dist/2023-03-07/rust-std-beta-thumbv6m-none-eabi.tar.gz": "38ab6ccd205e1ae9c7599482927bfe42096ad02cef8660bc9aae345b1081e723",
+    "dist/2023-03-07/rust-std-beta-thumbv6m-none-eabi.tar.xz": "7d605918c0bf111a02fec102de688bee0f2f18e3583c004571710421741224f8",
+    "dist/2023-03-07/rust-std-beta-thumbv7em-none-eabi.tar.gz": "cc7b6933e5f16bc828b446289c561d9810a977a322bdd9e406fa9c5b3e3e925f",
+    "dist/2023-03-07/rust-std-beta-thumbv7em-none-eabi.tar.xz": "d42fffb2fb88bac3090a9d99bfb91405f9bac5b09b88b286f74a85deb31adb2d",
+    "dist/2023-03-07/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "63619f93d1047979d90cc37f6903d4d34c28c793f5d07d448b8f818049c0694c",
+    "dist/2023-03-07/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "3f9735ea8a2b340803e95d55bbd1d510b501e4cd5844a9334ee9cda5733f17cf",
+    "dist/2023-03-07/rust-std-beta-thumbv7m-none-eabi.tar.gz": "73581e242b9f002eb36dcf05594859419cbe77393a8b21e8e1f447aaad05b0d0",
+    "dist/2023-03-07/rust-std-beta-thumbv7m-none-eabi.tar.xz": "f582f14891696a51458b3fea2db8ad883012aab40a5d8cfe97b420d0ad7ab901",
+    "dist/2023-03-07/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "5036157df192a76a3bc5084e9c4e53d9151871c1bd86851c361a08d09779cb0e",
+    "dist/2023-03-07/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "6b85161caf4a45bdaff3f5428fc41b7bc81a216484c755b7cab297a4914b7c7f",
+    "dist/2023-03-07/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "b749800ef87d357cc010ba46305d6603a40f7c52be3c1778e6a88a2956b89bc2",
+    "dist/2023-03-07/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "622dcf6bfae396ddf89dd0935a3269cc4f86f5ccc7c83982a75b915600f19733",
+    "dist/2023-03-07/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "7ec9e547fc95900efd3f04cb6f76213be5da762d997c85e8ea8434cbc0c0eebd",
+    "dist/2023-03-07/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "358fca90a80aeefdcd829aa6d3a027d81ceec010cc42aef971285c7d31699fd6",
+    "dist/2023-03-07/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "4d87df24f8c466cf2193eec458ce4033926088004d88b3ec4b9c74ed1d137a8a",
+    "dist/2023-03-07/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "65ded045c0615432a6017524c24da2e66b3ecd83e8869e382a00f2407fd06441",
+    "dist/2023-03-07/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "f8e081253423ac6fb29d502267e8fc22a3409965bebdd331dd00420ba609511c",
+    "dist/2023-03-07/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "c69a893777fc2acc407832752ea51d4bad5c4741c4a256172e4ebddeb5f939a7",
+    "dist/2023-03-07/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "28a8d21a98af1f950bb3f62d6fd124bc2fab0c0c27a419c1fcc1a84d31191b8c",
+    "dist/2023-03-07/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "b0a774faa4acdbff7d7581617da76e759e073a8d75b435373d9737c4300a178b",
+    "dist/2023-03-07/rust-std-beta-wasm32-unknown-unknown.tar.gz": "2a785745d3129a25441572d221a30d4108a35abf3bd73a387a5d65a5df82ff18",
+    "dist/2023-03-07/rust-std-beta-wasm32-unknown-unknown.tar.xz": "b5a50098ad047748644c7f510cb2682c52499d12f02a1e94c59a4f904c8002e6",
+    "dist/2023-03-07/rust-std-beta-wasm32-wasi.tar.gz": "265fa8b315a5d39a35fb8d32d5e46c3c66f9608992a3d708ac90437818cfed45",
+    "dist/2023-03-07/rust-std-beta-wasm32-wasi.tar.xz": "26839f3ed020dbda8ba893492cf504d565e7e1af7cfec5ad76053443d1022839",
+    "dist/2023-03-07/rust-std-beta-x86_64-apple-darwin.tar.gz": "8322910f96d5e206fc3ad237b4cf456e9fc2be0cbb00a57bfc2625126fe84d12",
+    "dist/2023-03-07/rust-std-beta-x86_64-apple-darwin.tar.xz": "3b1d0288890649121ed4487ec6ef5986913bcad5d224e8fed6feb5fcf56a3b2c",
+    "dist/2023-03-07/rust-std-beta-x86_64-apple-ios.tar.gz": "ea0a805d90b4b18c0b525faf4eedd2827d1f009d3c7a5cdc084db60c54e86d72",
+    "dist/2023-03-07/rust-std-beta-x86_64-apple-ios.tar.xz": "86bbc9cb184cb3c18a0afa1b982e951ee1e2569fca23ae7f85efd29f26e21983",
+    "dist/2023-03-07/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "f6bab7e24104f142c62f6d12585725bca24496d45888b22b07d2cc50f2f7f11a",
+    "dist/2023-03-07/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "20a1ae7636cc1dd9daec73818ecba60c60162d2a016822f1d3e828f55fc4ef9a",
+    "dist/2023-03-07/rust-std-beta-x86_64-linux-android.tar.gz": "78e7cae3d09a115fdd447bac210a78595076c37287b6dc142f9c363d207e16f5",
+    "dist/2023-03-07/rust-std-beta-x86_64-linux-android.tar.xz": "f37fcdc813462bcd94b0a06e38e665da9e5c1b5704cd029a23498c003a0df0a2",
+    "dist/2023-03-07/rust-std-beta-x86_64-pc-solaris.tar.gz": "afb0facbc35bc80c9f23ba59b9367c95b907c944aa5e1eff0fcf9687ca1089cb",
+    "dist/2023-03-07/rust-std-beta-x86_64-pc-solaris.tar.xz": "c771fd343a9a2073a8170730936153698d94aed87aa15b52a04075a6bfedd4ba",
+    "dist/2023-03-07/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "c753b3450a584ec7614e20fe308653c2451cc1910de76da663ee5c53a451004b",
+    "dist/2023-03-07/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "0d072a92ee2d33dd6b6122d273ba8cdbbc7dbc4cf090ca7abbe08fbfb16d5f86",
+    "dist/2023-03-07/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "de23d40c1aefa660f1411bb0c17da4f16b093244c0d515861b0866aed1e06b07",
+    "dist/2023-03-07/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "6f7b6070ae06074f338fc9eae327bf219389b5f88ee7ae07eb1e290d277b0f8f",
+    "dist/2023-03-07/rust-std-beta-x86_64-sun-solaris.tar.gz": "f2d68b5119525110c29dbd19a747f3ad632f45facee5c437e6796a2a213c52d3",
+    "dist/2023-03-07/rust-std-beta-x86_64-sun-solaris.tar.xz": "2da196278cc5a2eba2400d5d2b13fe74b65e9daefda0a6231684baaf76982147",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "c922f51ac5c80630d9cf2b1a0f770bcd1c1d74180a716b9852d37a6621035c38",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "b6ae7c3cd80b12537d0802444be97acf9be5072c058d025ced07398b0651f45c",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-fuchsia.tar.gz": "2fa8a0fcba9ecd4ac6c47b22091a4f58708f96197f95dcc8075e80a4256fdb0e",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-fuchsia.tar.xz": "025575e750bc2e1b43e7bf288a87059c96629d0d7290a57cfd0e31f2d0efb9aa",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-illumos.tar.gz": "8cfc61094c5ea8eec46131c17deaa8dfaa900f75300b996abd167f527defbb3f",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-illumos.tar.xz": "2e7c57376dbf890dc7d6bb7a0b555ee791b147aea4924882a3a94f9b75347f43",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "4840a693353f759d2d9e3fa40df97f200f27106159a9b126698a6ce07c3a117c",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "9a13a8c8e16028d0e07608da8fbd0ea5b51d9d425230712adcbac679ef5fef9d",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "0ac015df12c5212ac61b5a691d982a4fd64a8f77653b3d41e47da974abecda9f",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "bc12d3599f60a5860a15958ea7d4dc537d64802a23bc75e37a7381d875d3de2d",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "10ae35f994f504db3f58f098e8af9bc15f0c8e878b0af8487b6975846dcaf5ee",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "6d46f12168472f6a82980987d02b7e646a0814219c809ce04c352048be0a2981",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "978d7e3df8d6a16af9461eed0fdf79745c8a3ac91dc7e53ac4670e1991916e59",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "f936f6d186df0efcbf1655e7d2436bdebf5cd56ff811802c9ff753f20f38579e",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-none.tar.gz": "9c76650dd06c6d679716e4215259720ff5abed7731621617b9a785bb1c1f3c88",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-none.tar.xz": "4ec0d0b2dc4d163db2967df2f16dfd822adba2d85e85fcb21984c84377b4a5c2",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-redox.tar.gz": "701342db468d8bd5c08b962adf3b2c34d83a10fe81936d3b91937b5667e3f5e9",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-redox.tar.xz": "1c32cbb84bf8f967de3fe71e63c3c0d28c799276d9c2b5f2b3afbe87e57f026a",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-uefi.tar.gz": "51492e36780f026b1485d2c0394bc232d8825f3317fd438b1f8eaf9b8d50712e",
+    "dist/2023-03-07/rust-std-beta-x86_64-unknown-uefi.tar.xz": "33e46267265e9ec7394932b197c598d48147a119bd7346614714590181c84884",
+    "dist/2023-03-07/rustc-beta-aarch64-apple-darwin.tar.gz": "16927a64c3e0737274ebe4c8e6423977d5f2d684751f678fd2dc5c6a6020ab4b",
+    "dist/2023-03-07/rustc-beta-aarch64-apple-darwin.tar.xz": "66f758933129e0b1856b477f364e04187316227b4853aee8a5f95f6c7ad60fac",
+    "dist/2023-03-07/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "10a7cd771929aee13937bab01ad1e6d19998cc4ef58816ad8306539140fe3dfc",
+    "dist/2023-03-07/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "1d9ce8c7728b1831ce564df9a8ee9502ddcfd83c764d0f8c5b941a9beb570fb9",
+    "dist/2023-03-07/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "d75924fdcaa76b064d018e612457a4f960536c51767f46fe20d5e90d41424d45",
+    "dist/2023-03-07/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "1956f0965e3065a5901f935c42b10e07783ca33a2a8b6f182a5104edc4d73a01",
+    "dist/2023-03-07/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "40fbf2a72485dadf04eaf2a128f631c02542cb53f0d2b2c26369e8b8ee08463a",
+    "dist/2023-03-07/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "cb7f9812a09ec7397ccb67f36484ce22425446940b65cdc4c72e823a6fab5ec1",
+    "dist/2023-03-07/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "bc95e80e02e822913eadf5319253e7422615468db1c9627d394992319c3e4d5d",
+    "dist/2023-03-07/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "5b089b4b531cbd43909518093f6cfb1e5d4df138ede86ef7cc0e0e1053a43452",
+    "dist/2023-03-07/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "030d2ec4494c9139966cbb833c1616a78b973f10409defbb39f936652ef97449",
+    "dist/2023-03-07/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "2b2a728780b1bd30ec0cbcf014cb8914ed423a46a97f330c23b7386d8aec2ab7",
+    "dist/2023-03-07/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "2406baa5db6a46e51c79201fde893089ad16f31a17b117509774ee76f16bcdad",
+    "dist/2023-03-07/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "d121bf988fe4225d1cee4b452a0d5aa1620c990456dd9002c0af179802dc33c8",
+    "dist/2023-03-07/rustc-beta-i686-pc-windows-gnu.tar.gz": "eb5d4ae35799c3ddacc77e946b9fe8c1ba88f193c14c58ff23ee7ad89bdc6d9d",
+    "dist/2023-03-07/rustc-beta-i686-pc-windows-gnu.tar.xz": "1aeb85967f6de2267024abab0bb46dec4ce3bd06e687af39745cb556c37a82fb",
+    "dist/2023-03-07/rustc-beta-i686-pc-windows-msvc.tar.gz": "be2b29bd8ac4214eb5dff5f51c30cabfe859bc02b994c87cb139af50889abced",
+    "dist/2023-03-07/rustc-beta-i686-pc-windows-msvc.tar.xz": "1c097877d03021b975f2968bda73301a541b7989eb217537ffa3ae079e576c5e",
+    "dist/2023-03-07/rustc-beta-i686-unknown-linux-gnu.tar.gz": "3066f0d3b0e0319c8e9bfcc2215bb16729611563cedb976de0356a050ea68357",
+    "dist/2023-03-07/rustc-beta-i686-unknown-linux-gnu.tar.xz": "3908a8675f8b5743ce407e12cd0a32f0144db9b38bb49f05c47e855973d1e8c8",
+    "dist/2023-03-07/rustc-beta-mips-unknown-linux-gnu.tar.gz": "7aad6a6e37fb7f4fe835c2bbe7d1deb36ef973b7c94f3969b003812f87a92ff0",
+    "dist/2023-03-07/rustc-beta-mips-unknown-linux-gnu.tar.xz": "29e434023a1d94aaa5003723e2bcd31588d674f2ae243109e34f8e88e141c58c",
+    "dist/2023-03-07/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "4b2e92cd5a01df031060d03d088829056039951ce8b7edd9549944a6f567e07e",
+    "dist/2023-03-07/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "7e82c3f1a6d5175e452abd4f321469063cb2007f9f33cb3302a5745f985aefb5",
+    "dist/2023-03-07/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "b9fb2eb2f43b7479efb227964141f3beb29db829f449830ee41ac83280366ac7",
+    "dist/2023-03-07/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "c4eedd1aa5ac1532387a3091525d9d94fa7979002e0399b351bdd8d3bd064475",
+    "dist/2023-03-07/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "03685364b7750002a9a88717170c4330052c0838de82727734ebcb2d8b0466bc",
+    "dist/2023-03-07/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "13834ad521e7a3439c56dac58a548f816a60cc2b4f0d25952fb610b0245cd141",
+    "dist/2023-03-07/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "840a15c851f96e9b6b662d0b39c947b922e54195b07822ab6b1e13d5c8206a32",
+    "dist/2023-03-07/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "5721cb8347f4e9e546a59cec5c89ff548a2dbe867e27107678da6862a435781f",
+    "dist/2023-03-07/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "bb0c56acb9bb9940e970f23649f0d41338950f2e1c97cbca5e2de673069dca54",
+    "dist/2023-03-07/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "89c102653c6d4f562ad32fbc2d1b82ef38917528a7da6a3219f7b232dac62fcd",
+    "dist/2023-03-07/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "7ca86f54a307ec8e4751a58d541745c900813ef9b355ba21442629ef6d965ea1",
+    "dist/2023-03-07/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "c88a9c0581a8e3d119c57b9825ea8052e448871ed9c64f7530528e7fc833acaa",
+    "dist/2023-03-07/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "48f8abaffc106eba05c903ec250aeff17a71efa88702459da0ba8be58e62c8c4",
+    "dist/2023-03-07/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "04c176b55b9fdb2fc123e1e012fb8e2dc3bee74861b6cfedf2c1ffbbb3320293",
+    "dist/2023-03-07/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "a908e7f868fcd71050f57e08d15648cd6da04a0f9d150d87739349fb9c87a515",
+    "dist/2023-03-07/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "75062df65fbf89ab1d5344a3471e2c6322f9124fb447b32f634fb6d41695d5c7",
+    "dist/2023-03-07/rustc-beta-x86_64-apple-darwin.tar.gz": "df5224bb128f668474b9702457f5a349144b3148f44ae77109c7ad78800a4c42",
+    "dist/2023-03-07/rustc-beta-x86_64-apple-darwin.tar.xz": "9d27f437e483025cbdb69804f05138ebf181dceda8d32a676ea72ea4f27e69c3",
+    "dist/2023-03-07/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "a7f05d2072c3d3eb7ea88c09ec24a2ce0007ad31df5d3405c6766a68f2fd8ff4",
+    "dist/2023-03-07/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5e6477ac67b7db05caf15704541db112846415523c483df123d5f566e33afae4",
+    "dist/2023-03-07/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "3a9fd984f8a6673494859dce2dda6be7293effdc3ff7b4620b1078ba346150eb",
+    "dist/2023-03-07/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "5a12779df3e03ecb9ec334c02245f4dd779a4763ee789a9d6c72c244fed5b444",
+    "dist/2023-03-07/rustc-beta-x86_64-unknown-freebsd.tar.gz": "dd04e308e72a9cee60db732a17f12e1acbf279fd07efc232648087b765338f44",
+    "dist/2023-03-07/rustc-beta-x86_64-unknown-freebsd.tar.xz": "1dd44474ba9956abcdb0aa9d50c39fc7dcc3a78cd56450009bf4ee10cd94ef2e",
+    "dist/2023-03-07/rustc-beta-x86_64-unknown-illumos.tar.gz": "0db8082563772e480dfa71851182fd8a45cf6776d486e02204d92af0784c86a6",
+    "dist/2023-03-07/rustc-beta-x86_64-unknown-illumos.tar.xz": "eef088e452e105bffe4d28d38d1eacd4982253f0d59cdeb1f406068961699e0c",
+    "dist/2023-03-07/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "b767ffb06f21b1be530d79a81d8550680d15fd511de5cafae6da9da71017362b",
+    "dist/2023-03-07/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "d62e8956025dca9d6a9259cc8a35c6d364d161648adb91b50f1fe7e2aec5eb1b",
+    "dist/2023-03-07/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "aeb32342fc36171ae54b8677348dee02b10207bc85da773a1c7bacfac5e736fb",
+    "dist/2023-03-07/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "b051ffe45858f1ae2e60461183e4181a1b5c3fa4b349788416fb80b3e3fe39ea",
+    "dist/2023-03-07/rustc-beta-x86_64-unknown-netbsd.tar.gz": "2e5ed0ad450602ce32de9509e5317b1b205d4b715f716befb0389f6f6ad94cda",
+    "dist/2023-03-07/rustc-beta-x86_64-unknown-netbsd.tar.xz": "9347db918ca8139f0d816f297d327f48039f02e1d9d9f443fc0f46fb260c8901",
+    "dist/2023-03-07/rustc-nightly-aarch64-apple-darwin.tar.gz": "034c90c20d39fd2384b03ad2a756d3ca28a7447423bd709a0ade19374aa0fb05",
+    "dist/2023-03-07/rustc-nightly-aarch64-apple-darwin.tar.xz": "89d6d968fd5e55a950a798f06a09e1a776cf11dccc94b8123c21c55ebf55e9b7",
+    "dist/2023-03-07/rustc-nightly-aarch64-pc-windows-msvc.tar.gz": "809733a64b50a7c9c637afb442e45c4424a0fec96d921cfb0c8a7b30fa52edf7",
+    "dist/2023-03-07/rustc-nightly-aarch64-pc-windows-msvc.tar.xz": "03057ff6c4ae76618edea292f49abfcdcad09615a6164186348aba218936c3f0",
+    "dist/2023-03-07/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz": "e34521e27196fae399e0cbec28700ac409a829cf365bf5b9a7dc5530af61b93e",
+    "dist/2023-03-07/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "e17a9773d58ff0f48cce6c86326cbc33c4e0e8ce08f1a6d475481af9771ae6d6",
+    "dist/2023-03-07/rustc-nightly-aarch64-unknown-linux-musl.tar.gz": "01fffcbc734b7de28773a658178534a2cd4d262b156161abd6e5d1d471b45181",
+    "dist/2023-03-07/rustc-nightly-aarch64-unknown-linux-musl.tar.xz": "84c0c9d65f00f259df87e78bbe03d0f31075e70b71c587ca580e63604ee654e9",
+    "dist/2023-03-07/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz": "215cc518a7caacd106ffaaf28f709d1ddb3b4595acdf8574866d4e351576330d",
+    "dist/2023-03-07/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz": "f50d088adf616f3c25d095254b93d9032a41e5c6a3906afee959b223d6205dfe",
+    "dist/2023-03-07/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz": "a902efadc47040841653e67f918814a16242312c79ef11c10d69ba9999473c88",
+    "dist/2023-03-07/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz": "d608e664a5ce02b246b6b00910bdcb5f09e565e41cefbbb8efc579ac9a73c810",
+    "dist/2023-03-07/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "9e8151095f851f71c1d72d41e4ac63ee0dcc81d0f172ce9df4143b6499047aff",
+    "dist/2023-03-07/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "285530c33e600a4df44fd06abeac8e48aa5c084386c4cbe78e797c54f85d01ec",
+    "dist/2023-03-07/rustc-nightly-i686-pc-windows-gnu.tar.gz": "c0e245e17691d38d9f69164e5d9e02d08b5c2355f6fa9cea4bacf50af672c67f",
+    "dist/2023-03-07/rustc-nightly-i686-pc-windows-gnu.tar.xz": "d0c0e699cde96fb23ad5bcc7a8dbf94c86271404b72055bd3382eb29ae4ea85a",
+    "dist/2023-03-07/rustc-nightly-i686-pc-windows-msvc.tar.gz": "b083a065a973394293c11369199385a96d79a6cac5c9d695848e7ac2e51507af",
+    "dist/2023-03-07/rustc-nightly-i686-pc-windows-msvc.tar.xz": "b819b9af08383249f99f0137b636ac42ce84e3e5220c9e0fc1d9e0d348dca54f",
+    "dist/2023-03-07/rustc-nightly-i686-unknown-linux-gnu.tar.gz": "7337d5bc52c0e18c24546b04777ac24461b34e31a59d7df1611f70aee483528f",
+    "dist/2023-03-07/rustc-nightly-i686-unknown-linux-gnu.tar.xz": "efaae84475ddb1845fca470d6d77d842da4e2ad0cca0b2c1e9210c6fce3ff08c",
+    "dist/2023-03-07/rustc-nightly-mips-unknown-linux-gnu.tar.gz": "bd12029bcf9539959c9c9451093cf51ed9db6c7e26b9b9a3bf8617e481b9f094",
+    "dist/2023-03-07/rustc-nightly-mips-unknown-linux-gnu.tar.xz": "b9ea393526c68b9b502d81387cd4a1db7eeddad61467d2442be7c30d210727d8",
+    "dist/2023-03-07/rustc-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "997b37b199cc270b5a832aa608d18e0005a510efb587f154f899a22fb7f13639",
+    "dist/2023-03-07/rustc-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "e66332078213bf0cce845605d2f7faf28d859e3a98d12d61737ef782a9bdb187",
+    "dist/2023-03-07/rustc-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "8a7cbbeb0a9f82333068b51c49d33f694d91da327b1169bc44e9d570840d48d8",
+    "dist/2023-03-07/rustc-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "5eb5e2e270a4a475ef2933fe34c764dc6cfaaae423b0d1acb5313fda970f98ba",
+    "dist/2023-03-07/rustc-nightly-mipsel-unknown-linux-gnu.tar.gz": "3140ecca2db80b80118a08cc3fc7ac2989054338525bcc1fe0e2ef1fb5f742bd",
+    "dist/2023-03-07/rustc-nightly-mipsel-unknown-linux-gnu.tar.xz": "0432d418a81564af612a5dac562d7f4d72d7a18ac25260ad183609380efb6bc5",
+    "dist/2023-03-07/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz": "5be5fa12eafd82618c1f3f611351f23af1150c48b5e02f80f5b4252ec45c11dc",
+    "dist/2023-03-07/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz": "c288c46b8f077ee604d6de6286dc908086383be91ba17700c3f6273d064c6d82",
+    "dist/2023-03-07/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz": "de3fe2a9c4c87c5d622a1375dd4fd68064bcd2e5c36dbbc92b95ee42c8ad839e",
+    "dist/2023-03-07/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz": "b2fbb76cc9e323d0e61d927d7aceff561074b6dbf9907ed3c8dfd867d1308bd8",
+    "dist/2023-03-07/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "f16e202e7e2cfc3a47a0eddd5271fd3a9b7bac5f3c476ce619a249b88cc3ef0b",
+    "dist/2023-03-07/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "61a1cc7f9ce2e8d8ce62165ae7e8b8a53d5c78265641553305130f7a66c706ea",
+    "dist/2023-03-07/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "25ed59822afbd23edc354adb7e3bc361be9170ddd44fb15d7434e7240a66637b",
+    "dist/2023-03-07/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "fdadf6c8d04b99094385b4678015f23da571c3cc134b99e96c3964b15d91d9fe",
+    "dist/2023-03-07/rustc-nightly-s390x-unknown-linux-gnu.tar.gz": "b84099f98efd9554a005f8b6d8f15dc9bcd60f9f37856174306873631fa7597c",
+    "dist/2023-03-07/rustc-nightly-s390x-unknown-linux-gnu.tar.xz": "608f5a3a1628306618126f94349171566d9a38f14f58875ec1b1e990bd7b1b20",
+    "dist/2023-03-07/rustc-nightly-x86_64-apple-darwin.tar.gz": "4d8b094bf5c608b55e5b618838dafff4b701be093d42aea388c998c2676b226a",
+    "dist/2023-03-07/rustc-nightly-x86_64-apple-darwin.tar.xz": "f11249dc7fd5d208b10b9ead00dc8baa410ce92f61f597e3a550c138e9145413",
+    "dist/2023-03-07/rustc-nightly-x86_64-pc-windows-gnu.tar.gz": "db689e50dbef48555609217d09205cd1e397770469a82a9c0ad1f2cf1dd1643b",
+    "dist/2023-03-07/rustc-nightly-x86_64-pc-windows-gnu.tar.xz": "36160f7b9a98a463d4e62ed18ff59f5aa34aedf25cf7a7bbd1e4f93dfbfc4a60",
+    "dist/2023-03-07/rustc-nightly-x86_64-pc-windows-msvc.tar.gz": "0b10bbbf73fa9a9524746b080d44bcb29d31f013ab809b4c06a71e626f637b4a",
+    "dist/2023-03-07/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "a96259b26388fbf7907df887aacd8059f87207b46bb84ca9b87c460040a17d21",
+    "dist/2023-03-07/rustc-nightly-x86_64-unknown-freebsd.tar.gz": "0327b112309ab37508c5bd814a77a50e8eb86b19705758ee0a3c09cc560f89cc",
+    "dist/2023-03-07/rustc-nightly-x86_64-unknown-freebsd.tar.xz": "a7715f358798fc2f78ae6cb08b46f58ad577b91d0aa286893f8f51fda6b2de57",
+    "dist/2023-03-07/rustc-nightly-x86_64-unknown-illumos.tar.gz": "ed8d664f8609211b3eff0a606f1d5b5f46eb8ab0095df626a26c3abccc518fab",
+    "dist/2023-03-07/rustc-nightly-x86_64-unknown-illumos.tar.xz": "10badd3e994e93bf48ff1aafc7c056ac525afd12ac4761c0be7af94e361faad5",
+    "dist/2023-03-07/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz": "77b7bf994db683057ce94871fb288a24ba41d9a8f5441dfa9a39f3e772f295e3",
+    "dist/2023-03-07/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "738db7237b08938d978a00b5b972f4c52f36a128ba103ddb67318a905c7e2d27",
+    "dist/2023-03-07/rustc-nightly-x86_64-unknown-linux-musl.tar.gz": "50c57bbf49ec12092dad9de0e559c18f2049de07a0edac4b596a71a2f25a5e0f",
+    "dist/2023-03-07/rustc-nightly-x86_64-unknown-linux-musl.tar.xz": "31af1fbb0f1288e6d7b8eb594cb1936257603038c1ce8b89399056f5d3e1e9c4",
+    "dist/2023-03-07/rustc-nightly-x86_64-unknown-netbsd.tar.gz": "0a9e395f0b74cc945458d4ad4176567e86cfded1a594eaa485baadb4794dcb64",
+    "dist/2023-03-07/rustc-nightly-x86_64-unknown-netbsd.tar.xz": "26ff4a12db2b583e2e0b87aeb3d3eb9d1edc3478bfd40ffeb7ebdbfb8d8b2987",
+    "dist/2023-03-07/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "498c7ca27319868d6d2cfb9448b516de1a12076523f092d6c0df10848ba73ff5",
+    "dist/2023-03-07/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "eec9591d608e13c34fc8108fe976ae2085d688416d82c71bf18f3b00e35a1442",
+    "dist/2023-03-07/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "e9822c7e59218e75af96657bc8a5c3a20c77209f6f1d8861c626aabe7ba9a61d",
+    "dist/2023-03-07/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "dbad704c1fcfbd8562f366017c514aa90874de6028a9b41764ab7d78a72df6bf",
+    "dist/2023-03-07/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "5529210f57a0128889c19491846ff7c6f214d3a81d0619ee8dbd840f5f6f84a7",
+    "dist/2023-03-07/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "d59160d2f737322d401e864ae6b7be47f784a334c7cb378a0bbc2769e975945a",
+    "dist/2023-03-07/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "ab98e6c8fa7998065e0aaf211559d71405cc6e1910e3799889a27bdeea8c620f",
+    "dist/2023-03-07/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "04ca84fc64c1d211bd29f99b278d9072babbd1e0e9009d9f6f8f1b05f93a70ca",
+    "dist/2023-03-07/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "e80942fde81d3b54c4d0fc73576eebcda215535e4d80093f2a68f434958c0d9a",
+    "dist/2023-03-07/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "a9f10f9a51d3e3564f40c65f6d50c8ef67b4e074981f06f4d3b66aa398883f42",
+    "dist/2023-03-07/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "a5566343b6e3abadb152cd4a325735830aa9a60d5f2f87ef1aff66bbde276b14",
+    "dist/2023-03-07/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "9682e6c4a153d5083b0b360ed9248772da89f05f1142a6f297fc67218b60f298",
+    "dist/2023-03-07/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "51c14ab7679c23825e3a5b9637035768fd43f1e2787a12e431699710f4324998",
+    "dist/2023-03-07/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "f44893b879649a288c77b826e7e10202a2d3a5b8a8b123d8a030e69671a3ac43",
+    "dist/2023-03-07/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "7d5a0e567d8efd65b06b4a75ddc50e7bc2e36b42abaeab15147e970688c0bd07",
+    "dist/2023-03-07/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "541d5cb3d7beff1c0f9f2ea4a521303a372c2b6f4476d76bcfce4974a2753dfa",
+    "dist/2023-03-07/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "ccc65022f10cf0d7b8228806742c5163cd77edfcc2624894b96b2c9d6d974da4",
+    "dist/2023-03-07/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "fccfae7200edd30cd1b6083d00a400641b77e0a4a6e3bf2573710964c896c0d1",
+    "dist/2023-03-07/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "eed06879dacc571c289745a943de9bde2e39bee79ab5a5de0304fdc00e116855",
+    "dist/2023-03-07/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "cb1ed1cf09ce5cdbec931ea27b6fccd37b63108c780ae21c1756c68e0415c59b",
+    "dist/2023-03-07/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "b0681834694c5aa27c404d2328a5ce3e3dcc8a0b146fcd9d47113655cf94c948",
+    "dist/2023-03-07/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "a246b3e7c6ad436ad7523607bcf3a1fc42a66dd9da6a401fdaba5724fdf6801c",
+    "dist/2023-03-07/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "fa5b4d24c046b01b981fb81540155af5677490f2ac151418fa7791ec0f5aed56",
+    "dist/2023-03-07/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "b28148883461e905440ba25f755dc6a46c393a69a4cea48044e376fb90caa44b",
+    "dist/2023-03-07/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "ff37f00813b2ef0c206fb66cd383f87a089fad6a3746a9d62b27109557eb0097",
+    "dist/2023-03-07/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "2132cfd61404cfdad4e21ad95066836c77863756d46abc1fd2b702f46b3c7fac",
+    "dist/2023-03-07/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "89d1e41fd9bdd76c15faba83abfa1ffdadfffb6cd1b49c18e2d1333856296ee3",
+    "dist/2023-03-07/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "2353107ac3875f9cdf690b6684941c2def1c240416208dee58f58e78eefbd96e",
+    "dist/2023-03-07/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "b6e0882de92b73d540d22df393750646487dcf12c11b0bdad01265ce5cd6275f",
+    "dist/2023-03-07/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "c64967a706e7448f97d40b50356672b03f2731fde3488084007bbe7cd07409a6",
+    "dist/2023-03-07/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "d7d829f5a23aa25b320cd4f4c12d2db11d7e36c67a9396de7426933169159b62",
+    "dist/2023-03-07/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "1080d035d29fb9f8e1c007796e38164261ba19d4362b847d571eb7d3a6281d5c",
+    "dist/2023-03-07/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "874d841241b37072a6fb6c8d70f0afc9535ffb47793270b3a2a5c96ba46b7ec2",
+    "dist/2023-03-07/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "7ede80fb9a1aa27380d764d04e587a30fb6aee36138b145e32d518cbe8ec95b5",
+    "dist/2023-03-07/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "e1ec7d8b92740b0dff06e9424ac8d08b64e4aa85c5e8d46f9234fdeab5ad5e44",
+    "dist/2023-03-07/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "9058714e2f253ca681b24308a59bee006f636dff0b7571ebdf7c7687233b5a2f",
+    "dist/2023-03-07/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "6087e0abf78f2cb49240314cd31aa9bbfca02eb4918db4a2aaaa6758e8364560",
+    "dist/2023-03-07/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "2c775b1d4e2f3218a1d51f8ac79c63e8c2eabc46106e2a38d5bd1febcba7d12b",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "3a14e2b54773816cfdee1a835d2f758abfaacef36af6a7744c464b0ce5713c8b",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "3f6f7e5b9180f0114781b776a7f1bca72b208ddd102a9e44cebcd501eea7a31b",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "c92bf50f2a729af4b045184cd984bde0d97979cf8ae35975a1eaad5d8ae04195",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "c62b8f4862d0f8c38b890408c014be5d6d245f2a49d6f31a80c9447bbed4d8b4",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "8452a8704cb04ce2deef2cce2d9f2be066c5bd35aef323877ebef6f8f739710d",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "e694bb8697679196246f13031a9eef5129b0441a8c93c0292382b21cefab39a7",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "37f7ecfc0ba9314b2ec46ce202973cd7e36062a88070427ced9ffed3ad96c685",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "7aef4412810218743a85f1c7cce423394a327a708d31441441050bc1fcae0d80",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "70701d0bc637c282436e9ef6f18dadcb8068305ac64b1abb802bbc5054ff042c",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "2d8e170259a254cf6b1c5749a681040db70e2603b7231082483f03e2714765ba",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "7241cab5f93fc338fbb07acd2d38e2fa8615c4e6ebb0a53f51ac60c23838845f",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "2742e08cf5900ad3002809c632b8b8962325699307943ba2bafa0931204cc787",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "576c17a72e47fc743d60818bbfefe17c0223eb979cfed3046bf4797e6c2a6d26",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "25026a50665f53b7ac3e1e08b3a5a3a526411c8c18be6d64df6ab23ee0819b64",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "773679226499447a48cd823d324fc906a1d93f3fb5abc137920aa67ece410de9",
+    "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "53c88668c3c9ab6df7f3cace825a45616909bb28628ee8636a8ce86b77cf4bb5"
   }
 }
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 7d3033d2e59383fd76193daf9423c3d141972a7
+Subproject 15d090969743630bff549a1b068bcaa8174e5ee
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index e8531157e0f..a8926b29ac8 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
         span: Span,
         def_id: LocalDefId,
     ) {
-        if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) {
+        if !cx.tcx.has_attr(def_id, sym::test) {
             let expr = if is_async_fn(kind) {
                 match get_async_fn_body(cx.tcx, body) {
                     Some(b) => b,
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index 8a5a28c6b3d..8f68f90a2a1 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -181,7 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
                 self_ty,
                 ..
             }) = item.kind;
-            if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
+            if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
             if !item.span.from_expansion();
             if let Some(def_id) = trait_ref.trait_def_id();
             if cx.tcx.is_diagnostic_item(sym::Default, def_id);
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index b8428d66a5d..715348e869e 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -212,7 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
         }) = item.kind
         {
             let ty = cx.tcx.type_of(item.owner_id).subst_identity();
-            let is_automatically_derived = cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
+            let is_automatically_derived = cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
 
             check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
             check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index 29bdc46b647..eacbf6c6ec9 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -22,7 +22,7 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
 
 pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
     let attrs = cx.tcx.hir().attrs(item.hir_id());
-    let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
+    let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
     if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind {
         let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@@ -47,7 +47,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
         let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         let attrs = cx.tcx.hir().attrs(item.hir_id());
-        let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
+        let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
         } else if is_public
@@ -73,7 +73,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
 
         let attrs = cx.tcx.hir().attrs(item.hir_id());
-        let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
+        let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
         } else if let hir::TraitFn::Provided(eid) = *eid {
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 9fb73a371b8..ed0bd58c770 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -9,7 +9,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{sym, Span};
 use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
-use rustc_trait_selection::traits::{self, FulfillmentError};
+use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -79,8 +79,10 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
                 let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
                 let span = decl.output.span();
                 let infcx = cx.tcx.infer_ctxt().build();
+                let ocx = ObligationCtxt::new(&infcx);
                 let cause = traits::ObligationCause::misc(span, fn_def_id);
-                let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait);
+                ocx.register_bound(cause, cx.param_env, ret_ty, send_trait);
+                let send_errors = ocx.select_all_or_error();
                 if !send_errors.is_empty() {
                     span_lint_and_then(
                         cx,
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index d1d2db27c6f..fe28c526be3 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -167,7 +167,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
             Finite
         },
         ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)),
-        ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e),
+        ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e),
         ExprKind::Call(path, _) => {
             if let ExprKind::Path(ref qpath) = path.kind {
                 cx.qpath_res(qpath, path.hir_id)
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index b1bc10802e1..f0a1b1dfe56 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -124,8 +124,7 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t
 #[allow(clippy::too_many_lines)]
 fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult {
     match expr.kind {
-        ExprKind::Box(e)
-        | ExprKind::Unary(_, e)
+        ExprKind::Unary(_, e)
         | ExprKind::Cast(e, _)
         | ExprKind::Type(e, _)
         | ExprKind::Field(e, _)
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 3778eb4c732..f97c6bcb5d1 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::match_function_call_with_def_id;
 use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -175,16 +174,10 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
 fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
     if_chain! {
         if let Some(block_expr) = block.expr;
-        if let Some(args) = cx
-            .tcx
-            .lang_items()
-            .identity_future_fn()
-            .and_then(|def_id| match_function_call_with_def_id(cx, block_expr, def_id));
-        if args.len() == 1;
         if let Expr {
             kind: ExprKind::Closure(&Closure { body, .. }),
             ..
-        } = args[0];
+        } = block_expr;
         let closure_body = cx.tcx.hir().body(body);
         if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block));
         then {
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index b33a2478172..04225beeb70 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -321,7 +321,6 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
                     self.has_significant_drop = true;
                 }
             }
-            ExprKind::Box(..) |
             ExprKind::Array(..) |
             ExprKind::Call(..) |
             ExprKind::Unary(..) |
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
index 5201da52bbf..67618f7038a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -33,10 +33,6 @@ struct SortByKeyDetection {
 /// contains a and the other replaces it with b)
 fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool {
     match (&a_expr.kind, &b_expr.kind) {
-        // Two boxes with mirrored contents
-        (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => {
-            mirrored_exprs(left_expr, a_ident, right_expr, b_ident)
-        },
         // Two arrays with mirrored contents
         (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => {
             iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 79c1ae4861e..e3712190e67 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -127,8 +127,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         | ExprKind::Type(inner, _)
         | ExprKind::Unary(_, inner)
         | ExprKind::Field(inner, _)
-        | ExprKind::AddrOf(_, _, inner)
-        | ExprKind::Box(inner) => has_no_effect(cx, inner),
+        | ExprKind::AddrOf(_, _, inner) => has_no_effect(cx, inner),
         ExprKind::Struct(_, fields, ref base) => {
             !has_drop(cx, cx.typeck_results().expr_ty(expr))
                 && fields.iter().all(|field| has_no_effect(cx, field.expr))
@@ -234,8 +233,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
         | ExprKind::Type(inner, _)
         | ExprKind::Unary(_, inner)
         | ExprKind::Field(inner, _)
-        | ExprKind::AddrOf(_, _, inner)
-        | ExprKind::Box(inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
+        | ExprKind::AddrOf(_, _, inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
         ExprKind::Struct(_, fields, ref base) => {
             if has_drop(cx, cx.typeck_results().expr_ty(expr)) {
                 None
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
index 5aa3c6f2f93..a8c4823fe53 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
@@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if_chain! {
             if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind;
-            if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
+            if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
             if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
             if trait_ref.path.res.def_id() == eq_trait;
             then {
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 87f966ced0d..ae7d19624ba 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -213,8 +213,7 @@ fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_
     }
     loop {
         expr = match expr.kind {
-            ExprKind::Box(e)
-            | ExprKind::AddrOf(_, _, e)
+            ExprKind::AddrOf(_, _, e)
             | ExprKind::Block(
                 &Block {
                     stmts: [],
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index e2d90edec5a..e12681c0a0c 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -380,7 +380,6 @@ impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> {
             | hir::ExprKind::Assign(..)
             | hir::ExprKind::AssignOp(..)
             | hir::ExprKind::Binary(..)
-            | hir::ExprKind::Box(..)
             | hir::ExprKind::Call(..)
             | hir::ExprKind::Field(..)
             | hir::ExprKind::If(..)
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index f31c3fdb095..bc4adf1596d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -395,11 +395,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 }
                 self.expr(field!(let_expr.init));
             },
-            ExprKind::Box(inner) => {
-                bind!(self, inner);
-                kind!("Box({inner})");
-                self.expr(inner);
-            },
             ExprKind::Array(elements) => {
                 bind!(self, elements);
                 kind!("Array({elements})");
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 43f0df145f0..d3a6929f67e 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -112,7 +112,6 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) {
 /// Get the search patterns to use for the given expression
 fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
     match e.kind {
-        ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1),
         ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")),
         ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")),
         ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1),
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index ee2f816f181..babbc7294a1 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -199,8 +199,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 },
 
                 // Memory allocation, custom operator, loop, or call to an unknown function
-                ExprKind::Box(_)
-                | ExprKind::Unary(..)
+                ExprKind::Unary(..)
                 | ExprKind::Binary(..)
                 | ExprKind::Loop(..)
                 | ExprKind::Call(..) => self.eagerness = Lazy,
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 0603755f8a9..3a6d23ca5c1 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -249,7 +249,6 @@ impl HirEqInterExpr<'_, '_, '_> {
                 both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
                     && both(le, re, |l, r| self.eq_expr(l, r))
             },
-            (&ExprKind::Box(l), &ExprKind::Box(r)) => self.eq_expr(l, r),
             (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
                 self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
             },
@@ -628,7 +627,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_expr(j);
                 }
             },
-            ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => {
+            ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => {
                 self.hash_expr(e);
             },
             ExprKind::Call(fun, args) => {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 44b6b9f7b0b..29830557a44 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1904,16 +1904,7 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool {
 
 /// Peels away all the compiler generated code surrounding the body of an async function,
 pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
-    if let ExprKind::Call(
-        _,
-        &[
-            Expr {
-                kind: ExprKind::Closure(&Closure { body, .. }),
-                ..
-            },
-        ],
-    ) = body.value.kind
-    {
+    if let ExprKind::Closure(&Closure { body, .. }) = body.value.kind {
         if let ExprKind::Block(
             Block {
                 stmts: [],
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index e135bd9feee..c0e32068eca 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -533,6 +533,14 @@ struct FormatArgsValues<'tcx> {
 }
 
 impl<'tcx> FormatArgsValues<'tcx> {
+    fn new_empty(format_string_span: SpanData) -> Self {
+        Self {
+            value_args: Vec::new(),
+            pos_to_value_index: Vec::new(),
+            format_string_span,
+        }
+    }
+
     fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self {
         let mut pos_to_value_index = Vec::new();
         let mut value_args = Vec::new();
@@ -997,12 +1005,13 @@ impl<'tcx> FormatArgsExpn<'tcx> {
             .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?;
         let newline = macro_name == sym::format_args_nl;
 
+        // ::core::fmt::Arguments::new_const(pieces)
         // ::core::fmt::Arguments::new_v1(pieces, args)
         // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg)
-        if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind
+        if let ExprKind::Call(callee, [pieces, rest @ ..]) = expr.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind
             && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind
-            && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted")
+            && matches!(seg.ident.as_str(), "new_const" | "new_v1" | "new_v1_formatted")
         {
             let format_string = FormatString::new(cx, pieces)?;
 
@@ -1026,7 +1035,7 @@ impl<'tcx> FormatArgsExpn<'tcx> {
                 return None;
             }
 
-            let positions = if let Some(fmt_arg) = rest.first() {
+            let positions = if let Some(fmt_arg) = rest.get(1) {
                 // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse
                 // them.
 
@@ -1042,7 +1051,11 @@ impl<'tcx> FormatArgsExpn<'tcx> {
                 }))
             };
 
-            let values = FormatArgsValues::new(args, format_string.span.data());
+            let values = if let Some(args) = rest.first() {
+                FormatArgsValues::new(args, format_string.span.data())
+            } else {
+                FormatArgsValues::new_empty(format_string.span.data())
+            };
 
             let args = izip!(positions, parsed_args, parser.arg_places)
                 .map(|(position, parsed_arg, arg_span)| {
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 85bf28b708b..44cb5d5756a 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -133,7 +133,6 @@ impl<'a> Sugg<'a> {
 
         match expr.kind {
             hir::ExprKind::AddrOf(..)
-            | hir::ExprKind::Box(..)
             | hir::ExprKind::If(..)
             | hir::ExprKind::Let(..)
             | hir::ExprKind::Closure { .. }
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index d27a20bd4df..86a93f64fb7 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -600,7 +600,6 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
                 helper(typeck, false, e, f)?;
             },
             ExprKind::Block(&Block { expr: Some(e), .. }, _)
-            | ExprKind::Box(e)
             | ExprKind::Cast(e, _)
             | ExprKind::Unary(_, e) => {
                 helper(typeck, true, e, f)?;
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout
index c6acf24c21e..eb3e5189c82 100644
--- a/src/tools/clippy/tests/ui/author/blocks.stdout
+++ b/src/tools/clippy/tests/ui/author/blocks.stdout
@@ -43,11 +43,7 @@ if let ExprKind::Block(block, None) = expr.kind
 if let ExprKind::Closure(CaptureBy::Value, fn_decl, body_id, _, None) = expr.kind
     && let FnRetTy::DefaultReturn(_) = fn_decl.output
     && expr1 = &cx.tcx.hir().body(body_id).value
-    && let ExprKind::Call(func, args) = expr1.kind
-    && let ExprKind::Path(ref qpath) = func.kind
-    && matches!(qpath, QPath::LangItem(LangItem::IdentityFuture, _))
-    && args.len() == 1
-    && let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = args[0].kind
+    && let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = expr1.kind
     && let FnRetTy::DefaultReturn(_) = fn_decl1.output
     && expr2 = &cx.tcx.hir().body(body_id1).value
     && let ExprKind::Block(block, None) = expr2.kind
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index 0db043a4fca..85fd6523c82 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -26,4 +26,10 @@ libc = "0.2"
 
 [target.'cfg(windows)'.dependencies]
 miow = "0.5"
-winapi = { version = "0.3", features = ["winerror"] }
+
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
+features = [
+    "Win32_Foundation",
+    "Win32_System_Diagnostics_Debug",
+]
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 7fe2e6257d9..7691f5c32b2 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -9,7 +9,7 @@ use std::str::FromStr;
 
 use crate::util::{add_dylib_path, PathBufExt};
 use lazycell::LazyCell;
-use test::ColorConfig;
+use test::{ColorConfig, OutputFormat};
 
 #[derive(Clone, Copy, PartialEq, Debug)]
 pub enum Mode {
@@ -337,7 +337,7 @@ pub struct Config {
     pub verbose: bool,
 
     /// Print one character per test instead of one line
-    pub quiet: bool,
+    pub format: OutputFormat,
 
     /// Whether to use colors in test.
     pub color: ColorConfig,
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index d9b39927ca4..22a0b1d13be 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -1047,6 +1047,16 @@ pub fn make_test_description<R: Read>(
         name,
         ignore,
         ignore_message,
+        #[cfg(not(bootstrap))]
+        source_file: "",
+        #[cfg(not(bootstrap))]
+        start_line: 0,
+        #[cfg(not(bootstrap))]
+        start_col: 0,
+        #[cfg(not(bootstrap))]
+        end_line: 0,
+        #[cfg(not(bootstrap))]
+        end_col: 0,
         should_panic,
         compile_fail: false,
         no_run: false,
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 1760c29ec66..cbaa599f793 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -114,6 +114,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         )
         .optflag("", "quiet", "print one character per test instead of one line")
         .optopt("", "color", "coloring: auto, always, never", "WHEN")
+        .optflag("", "json", "emit json output instead of plaintext output")
         .optopt("", "logfile", "file to log test execution to", "FILE")
         .optopt("", "target", "the target to build for", "TARGET")
         .optopt("", "host", "the host to build for", "HOST")
@@ -281,7 +282,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
             && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
         lldb_python_dir: matches.opt_str("lldb-python-dir"),
         verbose: matches.opt_present("verbose"),
-        quiet: matches.opt_present("quiet"),
+        format: match (matches.opt_present("quiet"), matches.opt_present("json")) {
+            (true, true) => panic!("--quiet and --json are incompatible"),
+            (true, false) => test::OutputFormat::Terse,
+            (false, true) => test::OutputFormat::Json,
+            (false, false) => test::OutputFormat::Pretty,
+        },
         only_modified: matches.opt_present("only-modified"),
         color,
         remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from),
@@ -339,7 +345,7 @@ pub fn log_config(config: &Config) {
     logv(c, format!("ar: {}", config.ar));
     logv(c, format!("linker: {:?}", config.linker));
     logv(c, format!("verbose: {}", config.verbose));
-    logv(c, format!("quiet: {}", config.quiet));
+    logv(c, format!("format: {:?}", config.format));
     logv(c, "\n".to_string());
 }
 
@@ -416,7 +422,7 @@ pub fn run_tests(config: Config) {
             // easy to miss which tests failed, and as such fail to reproduce
             // the failure locally.
 
-            eprintln!(
+            println!(
                 "Some tests failed in compiletest suite={}{} mode={} host={} target={}",
                 config.suite,
                 config.compare_mode.map(|c| format!(" compare_mode={:?}", c)).unwrap_or_default(),
@@ -501,7 +507,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
         filters: config.filters.clone(),
         filter_exact: config.filter_exact,
         run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No },
-        format: if config.quiet { test::OutputFormat::Terse } else { test::OutputFormat::Pretty },
+        format: config.format,
         logfile: config.logfile.clone(),
         run_tests: true,
         bench_benchmarks: true,
diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs
index a5dc6859732..725f7a1515c 100644
--- a/src/tools/compiletest/src/read2.rs
+++ b/src/tools/compiletest/src/read2.rs
@@ -232,7 +232,7 @@ mod imp {
     use miow::iocp::{CompletionPort, CompletionStatus};
     use miow::pipe::NamedPipe;
     use miow::Overlapped;
-    use winapi::shared::winerror::ERROR_BROKEN_PIPE;
+    use windows::Win32::Foundation::ERROR_BROKEN_PIPE;
 
     struct Pipe<'a> {
         dst: &'a mut Vec<u8>,
@@ -295,7 +295,7 @@ mod imp {
             match self.pipe.read_overlapped(dst, self.overlapped.raw()) {
                 Ok(_) => Ok(()),
                 Err(e) => {
-                    if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) {
+                    if e.raw_os_error() == Some(ERROR_BROKEN_PIPE.0 as i32) {
                         self.done = true;
                         Ok(())
                     } else {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index a127875b55d..a4003072310 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -49,8 +49,10 @@ const FAKE_SRC_BASE: &str = "fake-test-src-base";
 #[cfg(windows)]
 fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
     use std::sync::Mutex;
-    use winapi::um::errhandlingapi::SetErrorMode;
-    use winapi::um::winbase::SEM_NOGPFAULTERRORBOX;
+
+    use windows::Win32::System::Diagnostics::Debug::{
+        SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE,
+    };
 
     static LOCK: Mutex<()> = Mutex::new(());
 
@@ -62,6 +64,7 @@ fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
     // termination by design. This mode is inherited by all child processes.
     unsafe {
         let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags
+        let old_mode = THREAD_ERROR_MODE(old_mode);
         SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX);
         let r = f();
         SetErrorMode(old_mode);
@@ -278,13 +281,15 @@ impl<'test> TestCx<'test> {
             Incremental => {
                 let revision =
                     self.revision.expect("incremental tests require a list of revisions");
-                if revision.starts_with("rpass") || revision.starts_with("rfail") {
+                if revision.starts_with("cpass")
+                    || revision.starts_with("rpass")
+                    || revision.starts_with("rfail")
+                {
                     true
                 } else if revision.starts_with("cfail") {
-                    // FIXME: would be nice if incremental revs could start with "cpass"
                     pm.is_some()
                 } else {
-                    panic!("revision name must begin with rpass, rfail, or cfail");
+                    panic!("revision name must begin with cpass, rpass, rfail, or cfail");
                 }
             }
             mode => panic!("unimplemented for mode {:?}", mode),
@@ -384,6 +389,20 @@ impl<'test> TestCx<'test> {
         }
     }
 
+    fn run_cpass_test(&self) {
+        let emit_metadata = self.should_emit_metadata(self.pass_mode());
+        let proc_res = self.compile_test(WillExecute::No, emit_metadata);
+
+        if !proc_res.status.success() {
+            self.fatal_proc_rec("compilation failed!", &proc_res);
+        }
+
+        // FIXME(#41968): Move this check to tidy?
+        if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() {
+            self.fatal("compile-pass tests with expected warnings should be moved to ui/");
+        }
+    }
+
     fn run_rpass_test(&self) {
         let emit_metadata = self.should_emit_metadata(self.pass_mode());
         let should_run = self.run_if_enabled();
@@ -393,17 +412,15 @@ impl<'test> TestCx<'test> {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
+        // FIXME(#41968): Move this check to tidy?
+        if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() {
+            self.fatal("run-pass tests with expected warnings should be moved to ui/");
+        }
+
         if let WillExecute::Disabled = should_run {
             return;
         }
 
-        // FIXME(#41968): Move this check to tidy?
-        let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
-        assert!(
-            expected_errors.is_empty(),
-            "run-pass tests with expected warnings should be moved to ui/"
-        );
-
         let proc_res = self.exec_compiled_test();
         if !proc_res.status.success() {
             self.fatal_proc_rec("test run failed!", &proc_res);
@@ -2913,10 +2930,11 @@ impl<'test> TestCx<'test> {
     fn run_incremental_test(&self) {
         // Basic plan for a test incremental/foo/bar.rs:
         // - load list of revisions rpass1, cfail2, rpass3
-        //   - each should begin with `rpass`, `cfail`, or `rfail`
-        //   - if `rpass`, expect compile and execution to succeed
+        //   - each should begin with `cpass`, `rpass`, `cfail`, or `rfail`
+        //   - if `cpass`, expect compilation to succeed, don't execute
+        //   - if `rpass`, expect compilation and execution to succeed
         //   - if `cfail`, expect compilation to fail
-        //   - if `rfail`, expect execution to fail
+        //   - if `rfail`, expect compilation to succeed and execution to fail
         // - create a directory build/foo/bar.incremental
         // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass1
         //   - because name of revision starts with "rpass", expect success
@@ -2940,7 +2958,12 @@ impl<'test> TestCx<'test> {
             print!("revision={:?} props={:#?}", revision, self.props);
         }
 
-        if revision.starts_with("rpass") {
+        if revision.starts_with("cpass") {
+            if self.props.should_ice {
+                self.fatal("can only use should-ice in cfail tests");
+            }
+            self.run_cpass_test();
+        } else if revision.starts_with("rpass") {
             if self.props.should_ice {
                 self.fatal("can only use should-ice in cfail tests");
             }
@@ -2953,7 +2976,7 @@ impl<'test> TestCx<'test> {
         } else if revision.starts_with("cfail") {
             self.run_cfail_test();
         } else {
-            self.fatal("revision name must begin with rpass, rfail, or cfail");
+            self.fatal("revision name must begin with cpass, rpass, rfail, or cfail");
         }
     }
 
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 138a69974e1..b71f48e4644 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -54,8 +54,8 @@ jobs:
             # contains package information of crates installed via `cargo install`.
             ~/.cargo/.crates.toml
             ~/.cargo/.crates2.json
-          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
-          restore-keys: ${{ runner.os }}-cargo
+          key: ${{ runner.os }}-cargo-reset20230315-${{ hashFiles('**/Cargo.lock') }}
+          restore-keys: ${{ runner.os }}-cargo-reset20230315
 
       - name: Install rustup-toolchain-install-master
         if: ${{ steps.cache.outputs.cache-hit != 'true' }}
@@ -106,8 +106,8 @@ jobs:
             # contains package information of crates installed via `cargo install`.
             ~/.cargo/.crates.toml
             ~/.cargo/.crates2.json
-          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
-          restore-keys: ${{ runner.os }}-cargo
+          key: ${{ runner.os }}-cargo-reset20230315-${{ hashFiles('**/Cargo.lock') }}
+          restore-keys: ${{ runner.os }}-cargo-reset20230315
 
       - name: Install rustup-toolchain-install-master
         if: ${{ steps.cache.outputs.cache-hit != 'true' }}
diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md
index 476075e9c91..bcdb623b090 100644
--- a/src/tools/miri/CONTRIBUTING.md
+++ b/src/tools/miri/CONTRIBUTING.md
@@ -129,18 +129,15 @@ development version of Miri using
 ./miri install
 ```
 
-and then you can use it as if it was installed by `rustup`.  Make sure you use
-the same toolchain when calling `cargo miri` that you used when installing Miri!
-Usually this means you have to write `cargo +miri miri ...` to select the `miri`
-toolchain that was installed by `./miri toolchain`.
+and then you can use it as if it was installed by `rustup` as a component of the
+`miri` toolchain. Note that the `miri` and `cargo-miri` executables are placed
+in the `miri` toolchain's sysroot to prevent conflicts with other toolchains.
+The Miri binaries in the `cargo` bin directory (usually `~/.cargo/bin`) are managed by rustup.
 
 There's a test for the cargo wrapper in the `test-cargo-miri` directory; run
 `./run-test.py` in there to execute it. Like `./miri test`, this respects the
 `MIRI_TEST_TARGET` environment variable to execute the test for another target.
 
-Note that installing Miri like this will "take away" Miri management from `rustup`.
-If you want to later go back to a rustup-installed Miri, run `rustup update`.
-
 ### Using a modified standard library
 
 Miri re-builds the standard library into a custom sysroot, so it is fairly easy
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 1086d0481c8..b70f7e0e556 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -15,6 +15,8 @@ for example:
   or an invalid enum discriminant)
 * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing
   for reference types
+* **Experimental**: Violations of the Tree Borrows aliasing rules, as an optional
+  alternative to [Stacked Borrows]
 * **Experimental**: Data races
 
 On top of that, Miri will also tell you about memory leaks: when there is memory
@@ -225,6 +227,26 @@ degree documented below):
   reduced feature set. We might ship Miri with a nightly even when some features
   on these targets regress.
 
+### Running tests in parallel
+
+Though it implements Rust threading, Miri itself is a single-threaded interpreter.
+This means that when running `cargo miri test`, you will probably see a dramatic
+increase in the amount of time it takes to run your whole test suite due to the
+inherent interpreter slowdown and a loss of parallelism.
+
+You can get your test suite's parallelism back by running `cargo miri nextest run -jN`
+(note that you will need [`cargo-nextest`](https://nexte.st) installed).
+This works because `cargo-nextest` collects a list of all tests then launches a
+separate `cargo miri run` for each test. You will need to specify a `-j` or `--test-threads`;
+by default `cargo miri nextest run` runs one test at a time. For more details, see the
+[`cargo-nextest` Miri documentation](https://nexte.st/book/miri.html).
+
+Note: This one-test-per-process model means that `cargo miri test` is able to detect data
+races where two tests race on a shared resource, but `cargo miri nextest run` will not detect
+such races.
+
+Note: `cargo-nextest` does not support doctests, see https://github.com/nextest-rs/nextest/issues/16
+
 ### Common Problems
 
 When using the above instructions, you may encounter a number of confusing compiler
@@ -337,9 +359,11 @@ to Miri failing to detect cases of undefined behavior in a program.
 * `-Zmiri-disable-data-race-detector` disables checking for data races.  Using
   this flag is **unsound**. This implies `-Zmiri-disable-weak-memory-emulation`.
 * `-Zmiri-disable-stacked-borrows` disables checking the experimental
-  [Stacked Borrows] aliasing rules.  This can make Miri run faster, but it also
-  means no aliasing violations will be detected.  Using this flag is **unsound**
-  (but the affected soundness rules are experimental).
+  aliasing rules to track borrows ([Stacked Borrows] and Tree Borrows).
+  This can make Miri run faster, but it also means no aliasing violations will
+  be detected. Using this flag is **unsound** (but the affected soundness rules
+  are experimental). Later flags take precedence: borrow tracking can be reactivated
+  by `-Zmiri-tree-borrows`.
 * `-Zmiri-disable-validation` disables enforcing validity invariants, which are
   enforced by default.  This is mostly useful to focus on other failures (such
   as out-of-bounds accesses) first.  Setting this flag means Miri can miss bugs
@@ -401,6 +425,9 @@ to Miri failing to detect cases of undefined behavior in a program.
 * `-Zmiri-track-weak-memory-loads` shows a backtrace when weak memory emulation returns an outdated
   value from a load. This can help diagnose problems that disappear under
   `-Zmiri-disable-weak-memory-emulation`.
+* `-Zmiri-tree-borrows` replaces [Stacked Borrows] with the Tree Borrows rules.
+  The soundness rules are already experimental without this flag, but even more
+  so with this flag.
 * `-Zmiri-force-page-size=<num>` overrides the default page size for an architecture, in multiples of 1k.
   `4` is default for most targets. This value should always be a power of 2 and nonzero.
 
@@ -415,7 +442,7 @@ Some native rustc `-Z` flags are also very relevant for Miri:
   functions.  This is needed so that Miri can execute such functions, so Miri
   sets this flag per default.
 * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri
-  enables this per default because it is needed for [Stacked Borrows].
+  enables this per default because it is needed for [Stacked Borrows] and Tree Borrows.
 
 Moreover, Miri recognizes some environment variables:
 
@@ -481,120 +508,8 @@ binaries, and as such worth documenting:
 ## Miri `extern` functions
 
 Miri provides some `extern` functions that programs can import to access
-Miri-specific functionality:
-
-```rust
-#[cfg(miri)]
-extern "Rust" {
-    /// Miri-provided extern function to mark the block `ptr` points to as a "root"
-    /// for some static memory. This memory and everything reachable by it is not
-    /// considered leaking even if it still exists when the program terminates.
-    ///
-    /// `ptr` has to point to the beginning of an allocated block.
-    fn miri_static_root(ptr: *const u8);
-
-    // Miri-provided extern function to get the amount of frames in the current backtrace.
-    // The `flags` argument must be `0`.
-    fn miri_backtrace_size(flags: u64) -> usize;
-
-    /// Miri-provided extern function to obtain a backtrace of the current call stack.
-    /// This writes a slice of pointers into `buf` - each pointer is an opaque value
-    /// that is only useful when passed to `miri_resolve_frame`.
-    /// `buf` must have `miri_backtrace_size(0) * pointer_size` bytes of space.
-    /// The `flags` argument must be `1`.
-    fn miri_get_backtrace(flags: u64, buf: *mut *mut ());
-
-    /// Miri-provided extern function to resolve a frame pointer obtained
-    /// from `miri_get_backtrace`. The `flags` argument must be `1`,
-    /// and `MiriFrame` should be declared as follows:
-    ///
-    /// ```rust
-    /// #[repr(C)]
-    /// struct MiriFrame {
-    ///     // The size of the name of the function being executed, encoded in UTF-8
-    ///     name_len: usize,
-    ///     // The size of filename of the function being executed, encoded in UTF-8
-    ///     filename_len: usize,
-    ///     // The line number currently being executed in `filename`, starting from '1'.
-    ///     lineno: u32,
-    ///     // The column number currently being executed in `filename`, starting from '1'.
-    ///     colno: u32,
-    ///     // The function pointer to the function currently being executed.
-    ///     // This can be compared against function pointers obtained by
-    ///     // casting a function (e.g. `my_fn as *mut ()`)
-    ///     fn_ptr: *mut ()
-    /// }
-    /// ```
-    ///
-    /// The fields must be declared in exactly the same order as they appear in `MiriFrame` above.
-    /// This function can be called on any thread (not just the one which obtained `frame`).
-    fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame;
-
-    /// Miri-provided extern function to get the name and filename of the frame provided by `miri_resolve_frame`.
-    /// `name_buf` and `filename_buf` should be allocated with the `name_len` and `filename_len` fields of `MiriFrame`.
-    /// The flags argument must be `0`.
-    fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8);
-
-    /// Miri-provided extern function to begin unwinding with the given payload.
-    ///
-    /// This is internal and unstable and should not be used; we give it here
-    /// just to be complete.
-    fn miri_start_panic(payload: *mut u8) -> !;
-
-    /// Miri-provided extern function to get the internal unique identifier for the allocation that a pointer
-    /// points to. If this pointer is invalid (not pointing to an allocation), interpretation will abort.
-    ///
-    /// This is only useful as an input to `miri_print_borrow_stacks`, and it is a separate call because
-    /// getting a pointer to an allocation at runtime can change the borrow stacks in the allocation.
-    /// This function should be considered unstable. It exists only to support `miri_print_borrow_stacks` and so
-    /// inherits all of its instability.
-    fn miri_get_alloc_id(ptr: *const ()) -> u64;
-
-    /// Miri-provided extern function to print (from the interpreter, not the program) the contents of all
-    /// borrow stacks in an allocation. The leftmost tag is the bottom of the stack.
-    /// The format of what this emits is unstable and may change at any time. In particular, users should be
-    /// aware that Miri will periodically attempt to garbage collect the contents of all stacks. Callers of
-    /// this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC.
-    ///
-    /// This function is extremely unstable. At any time the format of its output may change, its signature may
-    /// change, or it may be removed entirely.
-    fn miri_print_borrow_stacks(alloc_id: u64);
-
-    /// Miri-provided extern function to print (from the interpreter, not the
-    /// program) the contents of a section of program memory, as bytes. Bytes
-    /// written using this function will emerge from the interpreter's stdout.
-    fn miri_write_to_stdout(bytes: &[u8]);
-
-    /// Miri-provided extern function to print (from the interpreter, not the
-    /// program) the contents of a section of program memory, as bytes. Bytes
-    /// written using this function will emerge from the interpreter's stderr.
-    fn miri_write_to_stderr(bytes: &[u8]);
-
-    /// Miri-provided extern function to allocate memory from the interpreter.
-    /// 
-    /// This is useful when no fundamental way of allocating memory is
-    /// available, e.g. when using `no_std` + `alloc`.
-    fn miri_alloc(size: usize, align: usize) -> *mut u8;
-
-    /// Miri-provided extern function to deallocate memory.
-    fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
-
-    /// Convert a path from the host Miri runs on to the target Miri interprets.
-    /// Performs conversion of path separators as needed.
-    ///
-    /// Usually Miri performs this kind of conversion automatically. However, manual conversion
-    /// might be necessary when reading an environment variable that was set on the host
-    /// (such as TMPDIR) and using it as a target path.
-    ///
-    /// Only works with isolation disabled.
-    ///
-    /// `in` must point to a null-terminated string, and will be read as the input host path.
-    /// `out` must point to at least `out_size` many bytes, and the result will be stored there
-    /// with a null terminator.
-    /// Returns 0 if the `out` buffer was large enough, and the required size otherwise.
-    fn miri_host_to_target_path(path: *const std::ffi::c_char, out: *mut std::ffi::c_char, out_size: usize) -> usize;
-}
-```
+Miri-specific functionality. They are declared in
+[/tests/utils/miri\_extern.rs](/tests/utils/miri_extern.rs).
 
 ## Contributing and getting help
 
diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh
index 60450d09815..ef52a37fe31 100755
--- a/src/tools/miri/ci.sh
+++ b/src/tools/miri/ci.sh
@@ -62,8 +62,8 @@ function run_tests {
   if [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ]; then
     # These act up on Windows (`which miri` produces a filename that does not exist?!?),
     # so let's do this only on Linux. Also makes sure things work without these set.
-    export RUSTC=$(which rustc)
-    export MIRI=$(which miri)
+    export RUSTC=$(which rustc) # Produces a warning unless we also set MIRI
+    export MIRI=$(rustc +miri --print sysroot)/bin/miri
   fi
   mkdir -p .cargo
   echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml
diff --git a/src/tools/miri/miri b/src/tools/miri/miri
index 0c0bbbc7020..1073ff499ba 100755
--- a/src/tools/miri/miri
+++ b/src/tools/miri/miri
@@ -6,8 +6,8 @@ USAGE=$(cat <<"EOF"
 ./miri install <flags>:
 Installs the miri driver and cargo-miri. <flags> are passed to `cargo
 install`. Sets up the rpath such that the installed binary should work in any
-working directory. However, the rustup toolchain when invoking `cargo miri`
-needs to be the same one used for `./miri install`.
+working directory. Note that the binaries are placed in the `miri` toolchain
+sysroot, to prevent conflicts with other toolchains.
 
 ./miri build <flags>:
 Just build miri. <flags> are passed to `cargo build`.
@@ -281,8 +281,9 @@ find_sysroot() {
 case "$COMMAND" in
 install)
     # "--locked" to respect the Cargo.lock file if it exists.
-    $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked "$@"
-    $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked "$@"
+    # Install binaries to the miri toolchain's sysroot so they do not interact with other toolchains.
+    $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked --root "$SYSROOT" "$@"
+    $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --root "$SYSROOT" "$@"
     ;;
 check)
     # Check, and let caller control flags.
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 53ec1ba0821..18c2561242a 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-c4e0cd966062ca67daed20775f4e8a60c28e57df
+511364e7874dba9649a264100407e4bffe7b5425
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index a2caeb97297..0aea105ccc4 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -22,17 +22,18 @@ use log::debug;
 
 use rustc_data_structures::sync::Lrc;
 use rustc_driver::Compilation;
-use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node};
+use rustc_hir::{self as hir, Node};
 use rustc_interface::interface::Config;
 use rustc_middle::{
     middle::exported_symbols::{
         ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
     },
     ty::{query::ExternProviders, TyCtxt},
+    query::LocalCrate,
 };
 use rustc_session::{config::CrateType, search_paths::PathKind, CtfeBacktrace};
 
-use miri::{BacktraceStyle, ProvenanceMode, RetagFields};
+use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields};
 
 struct MiriCompilerCalls {
     miri_config: miri::MiriConfig,
@@ -107,8 +108,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
             config.override_queries = Some(|_, local_providers, _| {
                 // `exported_symbols` and `reachable_non_generics` provided by rustc always returns
                 // an empty result if `tcx.sess.opts.output_types.should_codegen()` is false.
-                local_providers.exported_symbols = |tcx, cnum| {
-                    assert_eq!(cnum, LOCAL_CRATE);
+                local_providers.exported_symbols = |tcx, LocalCrate| {
                     let reachable_set = tcx.with_stable_hashing_context(|hcx| {
                         tcx.reachable_set(()).to_sorted(&hcx, true)
                     });
@@ -317,6 +317,8 @@ fn main() {
             miri_config.validate = false;
         } else if arg == "-Zmiri-disable-stacked-borrows" {
             miri_config.borrow_tracker = None;
+        } else if arg == "-Zmiri-tree-borrows" {
+            miri_config.borrow_tracker = Some(BorrowTrackerMethod::TreeBorrows);
         } else if arg == "-Zmiri-disable-data-race-detector" {
             miri_config.data_race_detector = false;
             miri_config.weak_memory_emulation = false;
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
index 9f6cbe7f3c7..ed958329f95 100644
--- a/src/tools/miri/src/borrow_tracker/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/mod.rs
@@ -11,6 +11,7 @@ use rustc_target::abi::Size;
 
 use crate::*;
 pub mod stacked_borrows;
+pub mod tree_borrows;
 
 pub type CallId = NonZeroU64;
 
@@ -230,8 +231,10 @@ impl GlobalStateInner {
 /// Which borrow tracking method to use
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum BorrowTrackerMethod {
-    /// Stacked Borrows, as implemented in borrow_tracker/stacked
+    /// Stacked Borrows, as implemented in borrow_tracker/stacked_borrows
     StackedBorrows,
+    /// Tree borrows, as implemented in borrow_tracker/tree_borrows
+    TreeBorrows,
 }
 
 impl BorrowTrackerMethod {
@@ -258,6 +261,10 @@ impl GlobalStateInner {
                 AllocState::StackedBorrows(Box::new(RefCell::new(Stacks::new_allocation(
                     id, alloc_size, self, kind, machine,
                 )))),
+            BorrowTrackerMethod::TreeBorrows =>
+                AllocState::TreeBorrows(Box::new(RefCell::new(Tree::new_allocation(
+                    id, alloc_size, self, kind, machine,
+                )))),
         }
     }
 }
@@ -273,6 +280,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
         match method {
             BorrowTrackerMethod::StackedBorrows => this.sb_retag_ptr_value(kind, val),
+            BorrowTrackerMethod::TreeBorrows => this.tb_retag_ptr_value(kind, val),
         }
     }
 
@@ -285,6 +293,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
         match method {
             BorrowTrackerMethod::StackedBorrows => this.sb_retag_place_contents(kind, place),
+            BorrowTrackerMethod::TreeBorrows => this.tb_retag_place_contents(kind, place),
         }
     }
 
@@ -293,6 +302,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
         match method {
             BorrowTrackerMethod::StackedBorrows => this.sb_retag_return_place(),
+            BorrowTrackerMethod::TreeBorrows => this.tb_retag_return_place(),
         }
     }
 
@@ -301,6 +311,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
         match method {
             BorrowTrackerMethod::StackedBorrows => this.sb_expose_tag(alloc_id, tag),
+            BorrowTrackerMethod::TreeBorrows => this.tb_expose_tag(alloc_id, tag),
+        }
+    }
+
+    fn give_pointer_debug_name(
+        &mut self,
+        ptr: Pointer<Option<Provenance>>,
+        nth_parent: u8,
+        name: &str,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
+        match method {
+            BorrowTrackerMethod::StackedBorrows => {
+                this.tcx.tcx.sess.warn("Stacked Borrows does not support named pointers; `miri_pointer_name` is a no-op");
+                Ok(())
+            }
+            BorrowTrackerMethod::TreeBorrows =>
+                this.tb_give_pointer_debug_name(ptr, nth_parent, name),
+        }
+    }
+
+    fn print_borrow_state(&mut self, alloc_id: AllocId, show_unnamed: bool) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
+        match method {
+            BorrowTrackerMethod::StackedBorrows => this.print_stacks(alloc_id),
+            BorrowTrackerMethod::TreeBorrows => this.print_tree(alloc_id, show_unnamed),
         }
     }
 }
@@ -310,6 +348,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 pub enum AllocState {
     /// Data corresponding to Stacked Borrows
     StackedBorrows(Box<RefCell<stacked_borrows::AllocState>>),
+    /// Data corresponding to Tree Borrows
+    TreeBorrows(Box<RefCell<tree_borrows::AllocState>>),
 }
 
 impl machine::AllocExtra {
@@ -328,6 +368,14 @@ impl machine::AllocExtra {
             _ => panic!("expected Stacked Borrows borrow tracking, got something else"),
         }
     }
+
+    #[track_caller]
+    pub fn borrow_tracker_tb(&self) -> &RefCell<tree_borrows::AllocState> {
+        match self.borrow_tracker {
+            Some(AllocState::TreeBorrows(ref tb)) => tb,
+            _ => panic!("expected Tree Borrows borrow tracking, got something else"),
+        }
+    }
 }
 
 impl AllocState {
@@ -341,6 +389,14 @@ impl AllocState {
         match self {
             AllocState::StackedBorrows(sb) =>
                 sb.borrow_mut().before_memory_read(alloc_id, prov_extra, range, machine),
+            AllocState::TreeBorrows(tb) =>
+                tb.borrow_mut().before_memory_access(
+                    AccessKind::Read,
+                    alloc_id,
+                    prov_extra,
+                    range,
+                    machine,
+                ),
         }
     }
 
@@ -354,6 +410,14 @@ impl AllocState {
         match self {
             AllocState::StackedBorrows(sb) =>
                 sb.get_mut().before_memory_write(alloc_id, prov_extra, range, machine),
+            AllocState::TreeBorrows(tb) =>
+                tb.get_mut().before_memory_access(
+                    AccessKind::Write,
+                    alloc_id,
+                    prov_extra,
+                    range,
+                    machine,
+                ),
         }
     }
 
@@ -367,12 +431,15 @@ impl AllocState {
         match self {
             AllocState::StackedBorrows(sb) =>
                 sb.get_mut().before_memory_deallocation(alloc_id, prov_extra, range, machine),
+            AllocState::TreeBorrows(tb) =>
+                tb.get_mut().before_memory_deallocation(alloc_id, prov_extra, range, machine),
         }
     }
 
     pub fn remove_unreachable_tags(&self, tags: &FxHashSet<BorTag>) {
         match self {
             AllocState::StackedBorrows(sb) => sb.borrow_mut().remove_unreachable_tags(tags),
+            AllocState::TreeBorrows(tb) => tb.borrow_mut().remove_unreachable_tags(tags),
         }
     }
 }
@@ -381,6 +448,7 @@ impl VisitTags for AllocState {
     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         match self {
             AllocState::StackedBorrows(sb) => sb.visit_tags(visit),
+            AllocState::TreeBorrows(tb) => tb.visit_tags(visit),
         }
     }
 }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
new file mode 100644
index 00000000000..97bbdee1d44
--- /dev/null
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -0,0 +1,592 @@
+use rustc_data_structures::fx::FxHashMap;
+
+use std::fmt;
+use std::ops::Range;
+
+use crate::borrow_tracker::tree_borrows::{
+    err_tb_ub, perms::Permission, tree::LocationState, unimap::UniIndex,
+};
+use crate::borrow_tracker::{AccessKind, ProtectorKind};
+use crate::*;
+
+/// Some information that is irrelevant for the algorithm but very
+/// convenient to know about a tag for debugging and testing.
+#[derive(Clone, Debug)]
+pub struct NodeDebugInfo {
+    /// The tag in question.
+    pub tag: BorTag,
+    /// Name(s) that were associated with this tag (comma-separated).
+    /// Typically the name of the variable holding the corresponding
+    /// pointer in the source code.
+    /// Helps match tag numbers to human-readable names.
+    pub name: Option<String>,
+}
+impl NodeDebugInfo {
+    /// New node info with a name.
+    pub fn new(tag: BorTag) -> Self {
+        Self { tag, name: None }
+    }
+
+    /// Add a name to the tag. If a same tag is associated to several pointers,
+    /// it can have several names which will be separated by commas.
+    fn add_name(&mut self, name: &str) {
+        if let Some(ref mut prev_name) = &mut self.name {
+            prev_name.push(',');
+            prev_name.push_str(name);
+        } else {
+            self.name = Some(String::from(name));
+        }
+    }
+}
+
+impl fmt::Display for NodeDebugInfo {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(ref name) = self.name {
+            write!(f, "{tag:?} (also named '{name}')", tag = self.tag)
+        } else {
+            write!(f, "{tag:?}", tag = self.tag)
+        }
+    }
+}
+
+impl<'tcx> Tree {
+    /// Climb the tree to get the tag of a distant ancestor.
+    /// Allows operations on tags that are unreachable by the program
+    /// but still exist in the tree. Not guaranteed to perform consistently
+    /// if `tag-gc=1`.
+    fn nth_parent(&self, tag: BorTag, nth_parent: u8) -> Option<BorTag> {
+        let mut idx = self.tag_mapping.get(&tag).unwrap();
+        for _ in 0..nth_parent {
+            let node = self.nodes.get(idx).unwrap();
+            idx = node.parent?;
+        }
+        Some(self.nodes.get(idx).unwrap().tag)
+    }
+
+    /// Debug helper: assign name to tag.
+    pub fn give_pointer_debug_name(
+        &mut self,
+        tag: BorTag,
+        nth_parent: u8,
+        name: &str,
+    ) -> InterpResult<'tcx> {
+        let tag = self.nth_parent(tag, nth_parent).unwrap();
+        let idx = self.tag_mapping.get(&tag).unwrap();
+        if let Some(node) = self.nodes.get_mut(idx) {
+            node.debug_info.add_name(name);
+        } else {
+            eprintln!("Tag {tag:?} (to be named '{name}') not found!");
+        }
+        Ok(())
+    }
+
+    /// Debug helper: determines if the tree contains a tag.
+    pub fn is_allocation_of(&self, tag: BorTag) -> bool {
+        self.tag_mapping.contains_key(&tag)
+    }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub(super) enum TransitionError {
+    /// This access is not allowed because some parent tag has insufficient permissions.
+    /// For example, if a tag is `Frozen` and encounters a child write this will
+    /// produce a `ChildAccessForbidden(Frozen)`.
+    /// This kind of error can only occur on child accesses.
+    ChildAccessForbidden(Permission),
+    /// A protector was triggered due to an invalid transition that loses
+    /// too much permissions.
+    /// For example, if a protected tag goes from `Active` to `Frozen` due
+    /// to a foreign write this will produce a `ProtectedTransition(Active, Frozen)`.
+    /// This kind of error can only occur on foreign accesses.
+    ProtectedTransition(Permission, Permission),
+    /// Cannot deallocate because some tag in the allocation is strongly protected.
+    /// This kind of error can only occur on deallocations.
+    ProtectedDealloc,
+}
+
+/// Failures that can occur during the execution of Tree Borrows procedures.
+pub(super) struct TbError<'node> {
+    /// What failure occurred.
+    pub error_kind: TransitionError,
+    /// The tag on which the error was triggered.
+    /// On protector violations, this is the tag that was protected.
+    /// On accesses rejected due to insufficient permissions, this is the
+    /// tag that lacked those permissions.
+    pub faulty_tag: &'node NodeDebugInfo,
+    /// Whether this was a Read or Write access. This field is ignored
+    /// when the error was triggered by a deallocation.
+    pub access_kind: AccessKind,
+    /// Which tag the access that caused this error was made through, i.e.
+    /// which tag was used to read/write/deallocate.
+    pub tag_of_access: &'node NodeDebugInfo,
+}
+
+impl TbError<'_> {
+    /// Produce a UB error.
+    pub fn build<'tcx>(self) -> InterpErrorInfo<'tcx> {
+        use TransitionError::*;
+        err_tb_ub(match self.error_kind {
+            ChildAccessForbidden(perm) => {
+                format!(
+                    "{kind} through {initial} is forbidden because it is a child of {current} which is {perm}.",
+                    kind=self.access_kind,
+                    initial=self.tag_of_access,
+                    current=self.faulty_tag,
+                    perm=perm,
+                )
+            }
+            ProtectedTransition(start, end) => {
+                format!(
+                    "{kind} through {initial} is forbidden because it is a foreign tag for {current}, which would hence change from {start} to {end}, but {current} is protected",
+                    current=self.faulty_tag,
+                    start=start,
+                    end=end,
+                    kind=self.access_kind,
+                    initial=self.tag_of_access,
+                )
+            }
+            ProtectedDealloc => {
+                format!(
+                    "the allocation of {initial} also contains {current} which is strongly protected, cannot deallocate",
+                    initial=self.tag_of_access,
+                    current=self.faulty_tag,
+                )
+            }
+        }).into()
+    }
+}
+
+type S = &'static str;
+/// Pretty-printing details
+///
+/// Example:
+/// ```
+/// DisplayFmtWrapper {
+///     top: '>',
+///     bot: '<',
+///     warning_text: "Some tags have been hidden",
+/// }
+/// ```
+/// will wrap the entire text with
+/// ```text
+/// >>>>>>>>>>>>>>>>>>>>>>>>>>
+/// Some tags have been hidden
+///
+/// [ main display here ]
+///
+/// <<<<<<<<<<<<<<<<<<<<<<<<<<
+/// ```
+struct DisplayFmtWrapper {
+    /// Character repeated to make the upper border.
+    top: char,
+    /// Character repeated to make the lower border.
+    bot: char,
+    /// Warning about some tags (unnamed) being hidden.
+    warning_text: S,
+}
+
+/// Formating of the permissions on each range.
+///
+/// Example:
+/// ```
+/// DisplayFmtPermission {
+///     open: "[",
+///     sep: "|",
+///     close: "]",
+///     uninit: "___",
+///     range_sep: "..",
+/// }
+/// ```
+/// will show each permission line as
+/// ```text
+/// 0.. 1.. 2.. 3.. 4.. 5
+/// [Act|Res|Frz|Dis|___]
+/// ```
+struct DisplayFmtPermission {
+    /// Text that starts the permission block.
+    open: S,
+    /// Text that separates permissions on different ranges.
+    sep: S,
+    /// Text that ends the permission block.
+    close: S,
+    /// Text to show when a permission is not initialized.
+    /// Should have the same width as a `Permission`'s `.short_name()`, i.e.
+    /// 3 if using the `Res/Act/Frz/Dis` notation.
+    uninit: S,
+    /// Text to separate the `start` and `end` values of a range.
+    range_sep: S,
+}
+
+/// Formating of the tree structure.
+///
+/// Example:
+/// ```
+/// DisplayFmtPadding {
+///     join_middle: "|-",
+///     join_last: "'-",
+///     join_haschild: "-+-",
+///     join_default: "---",
+///     indent_middle: "| ",
+///     indent_last: "  ",
+/// }
+/// ```
+/// will show the tree as
+/// ```text
+/// -+- root
+///  |--+- a
+///  |  '--+- b
+///  |     '---- c
+///  |--+- d
+///  |  '---- e
+///  '---- f
+/// ```
+struct DisplayFmtPadding {
+    /// Connector for a child other than the last.
+    join_middle: S,
+    /// Connector for the last child. Should have the same width as `join_middle`.
+    join_last: S,
+    /// Connector for a node that itself has a child.
+    join_haschild: S,
+    /// Connector for a node that does not have a child. Should have the same width
+    /// as `join_haschild`.
+    join_default: S,
+    /// Indentation when there is a next child.
+    indent_middle: S,
+    /// Indentation for the last child.
+    indent_last: S,
+}
+/// How to show whether a location has been accessed
+///
+/// Example:
+/// ```
+/// DisplayFmtAccess {
+///     yes: " ",
+///     no: "?",
+///     meh: "_",
+/// }
+/// ```
+/// will show states as
+/// ```text
+///  Act
+/// ?Res
+/// ____
+/// ```
+struct DisplayFmtAccess {
+    /// Used when `State.initialized = true`.
+    yes: S,
+    /// Used when `State.initialized = false`.
+    /// Should have the same width as `yes`.
+    no: S,
+    /// Used when there is no `State`.
+    /// Should have the same width as `yes`.
+    meh: S,
+}
+
+/// All parameters to determine how the tree is formated.
+struct DisplayFmt {
+    wrapper: DisplayFmtWrapper,
+    perm: DisplayFmtPermission,
+    padding: DisplayFmtPadding,
+    accessed: DisplayFmtAccess,
+}
+impl DisplayFmt {
+    /// Print the permission with the format
+    /// ` Res`/` Re*`/` Act`/` Frz`/` Dis` for accessed locations
+    /// and `?Res`/`?Re*`/`?Act`/`?Frz`/`?Dis` for unaccessed locations.
+    fn print_perm(&self, perm: Option<LocationState>) -> String {
+        if let Some(perm) = perm {
+            format!(
+                "{ac}{st}",
+                ac = if perm.is_initialized() { self.accessed.yes } else { self.accessed.no },
+                st = perm.permission().short_name(),
+            )
+        } else {
+            format!("{}{}", self.accessed.meh, self.perm.uninit)
+        }
+    }
+
+    /// Print the tag with the format `<XYZ>` if the tag is unnamed,
+    /// and `<XYZ=name>` if the tag is named.
+    fn print_tag(&self, tag: BorTag, name: &Option<String>) -> String {
+        let printable_tag = tag.get();
+        if let Some(name) = name {
+            format!("<{printable_tag}={name}>")
+        } else {
+            format!("<{printable_tag}>")
+        }
+    }
+
+    /// Print extra text if the tag has a protector.
+    fn print_protector(&self, protector: Option<&ProtectorKind>) -> &'static str {
+        protector
+            .map(|p| {
+                match *p {
+                    ProtectorKind::WeakProtector => " Weakly protected",
+                    ProtectorKind::StrongProtector => " Strongly protected",
+                }
+            })
+            .unwrap_or("")
+    }
+}
+
+/// Track the indentation of the tree.
+struct DisplayIndent {
+    curr: String,
+}
+impl DisplayIndent {
+    fn new() -> Self {
+        Self { curr: "    ".to_string() }
+    }
+
+    /// Increment the indentation by one. Note: need to know if this
+    /// is the last child or not because the presence of other children
+    /// changes the way the indentation is shown.
+    fn increment(&mut self, formatter: &DisplayFmt, is_last: bool) {
+        self.curr.push_str(if is_last {
+            formatter.padding.indent_last
+        } else {
+            formatter.padding.indent_middle
+        });
+    }
+
+    /// Pop the last level of indentation.
+    fn decrement(&mut self, formatter: &DisplayFmt) {
+        for _ in 0..formatter.padding.indent_last.len() {
+            let _ = self.curr.pop();
+        }
+    }
+
+    /// Print the current indentation.
+    fn write(&self, s: &mut String) {
+        s.push_str(&self.curr);
+    }
+}
+
+/// Repeat a character a number of times.
+fn char_repeat(c: char, n: usize) -> String {
+    std::iter::once(c).cycle().take(n).collect::<String>()
+}
+
+/// Extracted information from the tree, in a form that is readily accessible
+/// for printing. I.e. resolve parent-child pointers into an actual tree,
+/// zip permissions with their tag, remove wrappers, stringify data.
+struct DisplayRepr {
+    tag: BorTag,
+    name: Option<String>,
+    rperm: Vec<Option<LocationState>>,
+    children: Vec<DisplayRepr>,
+}
+
+impl DisplayRepr {
+    fn from(tree: &Tree, show_unnamed: bool) -> Option<Self> {
+        let mut v = Vec::new();
+        extraction_aux(tree, tree.root, show_unnamed, &mut v);
+        let Some(root) = v.pop() else {
+            if show_unnamed {
+                unreachable!("This allocation contains no tags, not even a root. This should not happen.");
+            }
+            eprintln!("This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags.");
+            return None;
+        };
+        assert!(v.is_empty());
+        return Some(root);
+
+        fn extraction_aux(
+            tree: &Tree,
+            idx: UniIndex,
+            show_unnamed: bool,
+            acc: &mut Vec<DisplayRepr>,
+        ) {
+            let node = tree.nodes.get(idx).unwrap();
+            let name = node.debug_info.name.clone();
+            let children_sorted = {
+                let mut children = node.children.iter().cloned().collect::<Vec<_>>();
+                children.sort_by_key(|idx| tree.nodes.get(*idx).unwrap().tag);
+                children
+            };
+            if !show_unnamed && name.is_none() {
+                // We skip this node
+                for child_idx in children_sorted {
+                    extraction_aux(tree, child_idx, show_unnamed, acc);
+                }
+            } else {
+                // We take this node
+                let rperm = tree
+                    .rperms
+                    .iter_all()
+                    .map(move |(_offset, perms)| {
+                        let perm = perms.get(idx);
+                        perm.cloned()
+                    })
+                    .collect::<Vec<_>>();
+                let mut children = Vec::new();
+                for child_idx in children_sorted {
+                    extraction_aux(tree, child_idx, show_unnamed, &mut children);
+                }
+                acc.push(DisplayRepr { tag: node.tag, name, rperm, children });
+            }
+        }
+    }
+    fn print(
+        &self,
+        fmt: &DisplayFmt,
+        indenter: &mut DisplayIndent,
+        protected_tags: &FxHashMap<BorTag, ProtectorKind>,
+        ranges: Vec<Range<u64>>,
+        print_warning: bool,
+    ) {
+        let mut block = Vec::new();
+        // Push the header and compute the required paddings for the body.
+        // Header looks like this: `0.. 1.. 2.. 3.. 4.. 5.. 6.. 7.. 8`,
+        // and is properly aligned with the `|` of the body.
+        let (range_header, range_padding) = {
+            let mut header_top = String::new();
+            header_top.push_str("0..");
+            let mut padding = Vec::new();
+            for (i, range) in ranges.iter().enumerate() {
+                if i > 0 {
+                    header_top.push_str(fmt.perm.range_sep);
+                }
+                let s = range.end.to_string();
+                let l = s.chars().count() + fmt.perm.range_sep.chars().count();
+                {
+                    let target_len =
+                        fmt.perm.uninit.chars().count() + fmt.accessed.yes.chars().count() + 1;
+                    let tot_len = target_len.max(l);
+                    let header_top_pad_len = target_len.saturating_sub(l);
+                    let body_pad_len = tot_len.saturating_sub(target_len);
+                    header_top.push_str(&format!("{}{}", char_repeat(' ', header_top_pad_len), s));
+                    padding.push(body_pad_len);
+                }
+            }
+            ([header_top], padding)
+        };
+        for s in range_header {
+            block.push(s);
+        }
+        // This is the actual work
+        print_aux(
+            self,
+            &range_padding,
+            fmt,
+            indenter,
+            protected_tags,
+            true, /* root _is_ the last child */
+            &mut block,
+        );
+        // Then it's just prettifying it with a border of dashes.
+        {
+            let wr = &fmt.wrapper;
+            let max_width = {
+                let block_width = block.iter().map(|s| s.chars().count()).max().unwrap();
+                if print_warning {
+                    block_width.max(wr.warning_text.chars().count())
+                } else {
+                    block_width
+                }
+            };
+            eprintln!("{}", char_repeat(wr.top, max_width));
+            if print_warning {
+                eprintln!("{}", wr.warning_text,);
+            }
+            for line in block {
+                eprintln!("{line}");
+            }
+            eprintln!("{}", char_repeat(wr.bot, max_width));
+        }
+
+        // Here is the function that does the heavy lifting
+        fn print_aux(
+            tree: &DisplayRepr,
+            padding: &[usize],
+            fmt: &DisplayFmt,
+            indent: &mut DisplayIndent,
+            protected_tags: &FxHashMap<BorTag, ProtectorKind>,
+            is_last_child: bool,
+            acc: &mut Vec<String>,
+        ) {
+            let mut line = String::new();
+            // Format the permissions on each range.
+            // Looks like `| Act| Res| Res| Act|`.
+            line.push_str(fmt.perm.open);
+            for (i, (perm, &pad)) in tree.rperm.iter().zip(padding.iter()).enumerate() {
+                if i > 0 {
+                    line.push_str(fmt.perm.sep);
+                }
+                let show_perm = fmt.print_perm(*perm);
+                line.push_str(&format!("{}{}", char_repeat(' ', pad), show_perm));
+            }
+            line.push_str(fmt.perm.close);
+            // Format the tree structure.
+            // Main difficulty is handling the indentation properly.
+            indent.write(&mut line);
+            {
+                // padding
+                line.push_str(if is_last_child {
+                    fmt.padding.join_last
+                } else {
+                    fmt.padding.join_middle
+                });
+                line.push_str(fmt.padding.join_default);
+                line.push_str(if tree.children.is_empty() {
+                    fmt.padding.join_default
+                } else {
+                    fmt.padding.join_haschild
+                });
+                line.push_str(fmt.padding.join_default);
+                line.push_str(fmt.padding.join_default);
+            }
+            line.push_str(&fmt.print_tag(tree.tag, &tree.name));
+            let protector = protected_tags.get(&tree.tag);
+            line.push_str(fmt.print_protector(protector));
+            // Push the line to the accumulator then recurse.
+            acc.push(line);
+            let nb_children = tree.children.len();
+            for (i, child) in tree.children.iter().enumerate() {
+                indent.increment(fmt, is_last_child);
+                print_aux(child, padding, fmt, indent, protected_tags, i + 1 == nb_children, acc);
+                indent.decrement(fmt);
+            }
+        }
+    }
+}
+
+const DEFAULT_FORMATTER: DisplayFmt = DisplayFmt {
+    wrapper: DisplayFmtWrapper {
+        top: '─',
+        bot: '─',
+        warning_text: "Warning: this tree is indicative only. Some tags may have been hidden.",
+    },
+    perm: DisplayFmtPermission { open: "|", sep: "|", close: "|", uninit: "---", range_sep: ".." },
+    padding: DisplayFmtPadding {
+        join_middle: "├",
+        join_last: "â””",
+        indent_middle: "│ ",
+        indent_last: "  ",
+        join_haschild: "┬",
+        join_default: "─",
+    },
+    accessed: DisplayFmtAccess { yes: " ", no: "?", meh: "-" },
+};
+
+impl<'tcx> Tree {
+    /// Display the contents of the tree.
+    pub fn print_tree(
+        &self,
+        protected_tags: &FxHashMap<BorTag, ProtectorKind>,
+        show_unnamed: bool,
+    ) -> InterpResult<'tcx> {
+        let mut indenter = DisplayIndent::new();
+        let ranges = self.rperms.iter_all().map(|(range, _perms)| range).collect::<Vec<_>>();
+        if let Some(repr) = DisplayRepr::from(self, show_unnamed) {
+            repr.print(
+                &DEFAULT_FORMATTER,
+                &mut indenter,
+                protected_tags,
+                ranges,
+                /* print warning message about tags not shown */ !show_unnamed,
+            );
+        }
+        Ok(())
+    }
+}
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
new file mode 100644
index 00000000000..2297ceb1259
--- /dev/null
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -0,0 +1,539 @@
+use log::trace;
+
+use rustc_target::abi::{Abi, Size};
+
+use crate::borrow_tracker::{AccessKind, GlobalStateInner, ProtectorKind, RetagFields};
+use rustc_middle::{
+    mir::{Mutability, RetagKind},
+    ty::{
+        self,
+        layout::{HasParamEnv, LayoutOf},
+        Ty,
+    },
+};
+
+use crate::*;
+
+mod diagnostics;
+mod perms;
+mod tree;
+mod unimap;
+use perms::Permission;
+pub use tree::Tree;
+
+pub type AllocState = Tree;
+
+pub fn err_tb_ub<'tcx>(msg: String) -> InterpError<'tcx> {
+    err_machine_stop!(TerminationInfo::TreeBorrowsUb { msg })
+}
+
+impl<'tcx> Tree {
+    /// Create a new allocation, i.e. a new tree
+    pub fn new_allocation(
+        id: AllocId,
+        size: Size,
+        state: &mut GlobalStateInner,
+        _kind: MemoryKind<machine::MiriMemoryKind>,
+        machine: &MiriMachine<'_, 'tcx>,
+    ) -> Self {
+        let tag = state.base_ptr_tag(id, machine); // Fresh tag for the root
+        Tree::new(tag, size)
+    }
+
+    /// Check that an access on the entire range is permitted, and update
+    /// the tree.
+    pub fn before_memory_access(
+        &mut self,
+        access_kind: AccessKind,
+        alloc_id: AllocId,
+        prov: ProvenanceExtra,
+        range: AllocRange,
+        machine: &MiriMachine<'_, 'tcx>,
+    ) -> InterpResult<'tcx> {
+        trace!(
+            "{} with tag {:?}: {:?}, size {}",
+            access_kind,
+            prov,
+            Pointer::new(alloc_id, range.start),
+            range.size.bytes(),
+        );
+        // TODO: for now we bail out on wildcard pointers. Eventually we should
+        // handle them as much as we can.
+        let tag = match prov {
+            ProvenanceExtra::Concrete(tag) => tag,
+            ProvenanceExtra::Wildcard => return Ok(()),
+        };
+        let global = machine.borrow_tracker.as_ref().unwrap();
+        self.perform_access(access_kind, tag, range, global)
+    }
+
+    /// Check that this pointer has permission to deallocate this range.
+    pub fn before_memory_deallocation(
+        &mut self,
+        _alloc_id: AllocId,
+        prov: ProvenanceExtra,
+        range: AllocRange,
+        machine: &MiriMachine<'_, 'tcx>,
+    ) -> InterpResult<'tcx> {
+        // TODO: for now we bail out on wildcard pointers. Eventually we should
+        // handle them as much as we can.
+        let tag = match prov {
+            ProvenanceExtra::Concrete(tag) => tag,
+            ProvenanceExtra::Wildcard => return Ok(()),
+        };
+        let global = machine.borrow_tracker.as_ref().unwrap();
+        self.dealloc(tag, range, global)
+    }
+
+    pub fn expose_tag(&mut self, _tag: BorTag) {
+        // TODO
+    }
+}
+
+/// Policy for a new borrow.
+#[derive(Debug, Clone, Copy)]
+struct NewPermission {
+    /// Whether this borrow requires a read access on its parent.
+    /// `perform_read_access` is `true` for all pointers marked `dereferenceable`.
+    perform_read_access: bool,
+    /// Which permission should the pointer start with.
+    initial_state: Permission,
+    /// Whether this pointer is part of the arguments of a function call.
+    /// `protector` is `Some(_)` for all pointers marked `noalias`.
+    protector: Option<ProtectorKind>,
+}
+
+impl<'tcx> NewPermission {
+    /// Determine NewPermission of the reference from the type of the pointee.
+    fn from_ref_ty(
+        pointee: Ty<'tcx>,
+        mutability: Mutability,
+        kind: RetagKind,
+        cx: &crate::MiriInterpCx<'_, 'tcx>,
+    ) -> Option<Self> {
+        let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.param_env());
+        let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.param_env());
+        let initial_state = match mutability {
+            Mutability::Mut if ty_is_unpin => Permission::new_unique_2phase(ty_is_freeze),
+            Mutability::Not if ty_is_freeze => Permission::new_frozen(),
+            // Raw pointers never enter this function so they are not handled.
+            // However raw pointers are not the only pointers that take the parent
+            // tag, this also happens for `!Unpin` `&mut`s and interior mutable
+            // `&`s, which are excluded above.
+            _ => return None,
+        };
+        // This field happens to be redundant since right now we always do a read,
+        // but it could be useful in the future.
+        let perform_read_access = true;
+
+        let protector = (kind == RetagKind::FnEntry).then_some(ProtectorKind::StrongProtector);
+        Some(Self { perform_read_access, initial_state, protector })
+    }
+
+    // Boxes are not handled by `from_ref_ty`, they need special behavior
+    // implemented here.
+    fn from_box_ty(
+        ty: Ty<'tcx>,
+        kind: RetagKind,
+        cx: &crate::MiriInterpCx<'_, 'tcx>,
+    ) -> Option<Self> {
+        let pointee = ty.builtin_deref(true).unwrap().ty;
+        pointee.is_unpin(*cx.tcx, cx.param_env()).then_some(()).map(|()| {
+            // Regular `Unpin` box, give it `noalias` but only a weak protector
+            // because it is valid to deallocate it within the function.
+            let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.param_env());
+            Self {
+                perform_read_access: true,
+                initial_state: Permission::new_unique_2phase(ty_is_freeze),
+                protector: (kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector),
+            }
+        })
+    }
+}
+
+/// Retagging/reborrowing.
+/// Policy on which permission to grant to each pointer should be left to
+/// the implementation of NewPermission.
+impl<'mir: 'ecx, 'tcx: 'mir, 'ecx> EvalContextPrivExt<'mir, 'tcx, 'ecx>
+    for crate::MiriInterpCx<'mir, 'tcx>
+{
+}
+trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    /// Returns the `AllocId` the reborrow was done in, if there is some actual
+    /// memory associated with this pointer. Returns `None` if there is no actual
+    /// memory allocated. Also checks that the reborrow of size `ptr_size` is
+    /// within bounds of the allocation.
+    ///
+    /// Also returns the tag that the pointer should get, which is essentially
+    /// `if new_perm.is_some() { new_tag } else { parent_tag }` along with
+    /// some logging (always) and fake reads (if `new_perm` is
+    /// `Some(NewPermission { perform_read_access: true }`).
+    fn tb_reborrow(
+        &mut self,
+        place: &MPlaceTy<'tcx, Provenance>, // parent tag extracted from here
+        ptr_size: Size,
+        new_perm: Option<NewPermission>,
+        new_tag: BorTag,
+    ) -> InterpResult<'tcx, Option<(AllocId, BorTag)>> {
+        let this = self.eval_context_mut();
+
+        // It is crucial that this gets called on all code paths, to ensure we track tag creation.
+        let log_creation = |this: &MiriInterpCx<'mir, 'tcx>,
+                            loc: Option<(AllocId, Size, ProvenanceExtra)>| // alloc_id, base_offset, orig_tag
+         -> InterpResult<'tcx> {
+            let global = this.machine.borrow_tracker.as_ref().unwrap().borrow();
+            let ty = place.layout.ty;
+            if global.tracked_pointer_tags.contains(&new_tag) {
+                let kind_str = format!("{new_perm:?} (pointee type {ty})");
+                this.emit_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(
+                    new_tag.inner(),
+                    Some(kind_str),
+                    loc.map(|(alloc_id, base_offset, orig_tag)| (alloc_id, alloc_range(base_offset, ptr_size), orig_tag)),
+                ));
+            }
+            drop(global); // don't hold that reference any longer than we have to
+            Ok(())
+        };
+
+        let (alloc_id, base_offset, parent_prov) = if ptr_size > Size::ZERO {
+            this.ptr_get_alloc_id(place.ptr)?
+        } else {
+            match this.ptr_try_get_alloc_id(place.ptr) {
+                Ok(data) => data,
+                Err(_) => {
+                    // This pointer doesn't come with an AllocId, so there's no
+                    // memory to do retagging in.
+                    trace!(
+                        "reborrow of size 0: reference {:?} derived from {:?} (pointee {})",
+                        new_tag,
+                        place.ptr,
+                        place.layout.ty,
+                    );
+                    log_creation(this, None)?;
+                    return Ok(None);
+                }
+            }
+        };
+        let orig_tag = match parent_prov {
+            ProvenanceExtra::Wildcard => return Ok(None), // TODO: handle wildcard pointers
+            ProvenanceExtra::Concrete(tag) => tag,
+        };
+
+        // Protection against trying to get a reference to a vtable:
+        // vtables do not have an alloc_extra so the call to
+        // `get_alloc_extra` that follows fails.
+        let (alloc_size, _align, alloc_kind) = this.get_alloc_info(alloc_id);
+        if ptr_size == Size::ZERO && !matches!(alloc_kind, AllocKind::LiveData) {
+            return Ok(Some((alloc_id, orig_tag)));
+        }
+
+        log_creation(this, Some((alloc_id, base_offset, parent_prov)))?;
+
+        // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
+        if base_offset + ptr_size > alloc_size {
+            throw_ub!(PointerOutOfBounds {
+                alloc_id,
+                alloc_size,
+                ptr_offset: this.target_usize_to_isize(base_offset.bytes()),
+                ptr_size,
+                msg: CheckInAllocMsg::InboundsTest
+            });
+        }
+
+        trace!(
+            "reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
+            new_tag,
+            orig_tag,
+            place.layout.ty,
+            Pointer::new(alloc_id, base_offset),
+            ptr_size.bytes()
+        );
+
+        let Some(new_perm) = new_perm else { return Ok(Some((alloc_id, orig_tag))); };
+
+        if let Some(protect) = new_perm.protector {
+            // We register the protection in two different places.
+            // This makes creating a protector slower, but checking whether a tag
+            // is protected faster.
+            this.frame_mut().extra.borrow_tracker.as_mut().unwrap().protected_tags.push(new_tag);
+            this.machine
+                .borrow_tracker
+                .as_mut()
+                .expect("We should have borrow tracking data")
+                .get_mut()
+                .protected_tags
+                .insert(new_tag, protect);
+        }
+
+        let alloc_extra = this.get_alloc_extra(alloc_id)?;
+        let range = alloc_range(base_offset, ptr_size);
+        let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut();
+
+        if new_perm.perform_read_access {
+            // Count this reborrow as a read access
+            let global = &this.machine.borrow_tracker.as_ref().unwrap();
+            tree_borrows.perform_access(AccessKind::Read, orig_tag, range, global)?;
+            if let Some(data_race) = alloc_extra.data_race.as_ref() {
+                data_race.read(alloc_id, range, &this.machine)?;
+            }
+        }
+
+        // Record the parent-child pair in the tree.
+        tree_borrows.new_child(orig_tag, new_tag, new_perm.initial_state, range)?;
+        Ok(Some((alloc_id, new_tag)))
+    }
+
+    /// Retags an indidual pointer, returning the retagged version.
+    fn tb_retag_reference(
+        &mut self,
+        val: &ImmTy<'tcx, Provenance>,
+        new_perm: Option<NewPermission>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
+        let this = self.eval_context_mut();
+        // We want a place for where the ptr *points to*, so we get one.
+        let place = this.ref_to_mplace(val)?;
+
+        // Get a lower bound of the size of this place.
+        // (When `extern type` are involved, use the size of the known prefix.)
+        let size = this
+            .size_and_align_of_mplace(&place)?
+            .map(|(size, _)| size)
+            .unwrap_or(place.layout.size);
+
+        // This new tag is not guaranteed to actually be used.
+        //
+        // If you run out of tags, consider the following optimization: adjust `tb_reborrow`
+        // so that rather than taking as input a fresh tag and deciding whether it uses this
+        // one or the parent it instead just returns whether a new tag should be created.
+        // This will avoid creating tags than end up never being used.
+        let new_tag = this.machine.borrow_tracker.as_mut().unwrap().get_mut().new_ptr();
+
+        // Compute the actual reborrow.
+        let reborrowed = this.tb_reborrow(&place, size, new_perm, new_tag)?;
+
+        // Adjust pointer.
+        let new_place = place.map_provenance(|p| {
+            p.map(|prov| {
+                match reborrowed {
+                    Some((alloc_id, actual_tag)) => {
+                        // If `reborrow` could figure out the AllocId of this ptr, hard-code it into the new one.
+                        // Even if we started out with a wildcard, this newly retagged pointer is tied to that allocation.
+                        Provenance::Concrete { alloc_id, tag: actual_tag }
+                    }
+                    None => {
+                        // Looks like this has to stay a wildcard pointer.
+                        assert!(matches!(prov, Provenance::Wildcard));
+                        Provenance::Wildcard
+                    }
+                }
+            })
+        });
+
+        // Return new pointer.
+        Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout))
+    }
+}
+
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    /// Retag a pointer. References are passed to `from_ref_ty` and
+    /// raw pointers are never reborrowed.
+    fn tb_retag_ptr_value(
+        &mut self,
+        kind: RetagKind,
+        val: &ImmTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
+        let this = self.eval_context_mut();
+        let new_perm = if let &ty::Ref(_, pointee, mutability) = val.layout.ty.kind() {
+            NewPermission::from_ref_ty(pointee, mutability, kind, this)
+        } else {
+            None
+        };
+        this.tb_retag_reference(val, new_perm)
+    }
+
+    /// Retag all pointers that are stored in this place.
+    fn tb_retag_place_contents(
+        &mut self,
+        kind: RetagKind,
+        place: &PlaceTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let retag_fields = this.machine.borrow_tracker.as_mut().unwrap().get_mut().retag_fields;
+        let mut visitor = RetagVisitor { ecx: this, kind, retag_fields };
+        return visitor.visit_value(place);
+
+        // The actual visitor.
+        struct RetagVisitor<'ecx, 'mir, 'tcx> {
+            ecx: &'ecx mut MiriInterpCx<'mir, 'tcx>,
+            kind: RetagKind,
+            retag_fields: RetagFields,
+        }
+        impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> {
+            #[inline(always)] // yes this helps in our benchmarks
+            fn retag_ptr_inplace(
+                &mut self,
+                place: &PlaceTy<'tcx, Provenance>,
+                new_perm: Option<NewPermission>,
+            ) -> InterpResult<'tcx> {
+                let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?;
+                let val = self.ecx.tb_retag_reference(&val, new_perm)?;
+                self.ecx.write_immediate(*val, place)?;
+                Ok(())
+            }
+        }
+        impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>>
+            for RetagVisitor<'ecx, 'mir, 'tcx>
+        {
+            type V = PlaceTy<'tcx, Provenance>;
+
+            #[inline(always)]
+            fn ecx(&mut self) -> &mut MiriInterpCx<'mir, 'tcx> {
+                self.ecx
+            }
+
+            fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
+                let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
+                self.retag_ptr_inplace(place, new_perm)
+            }
+
+            fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
+                // If this place is smaller than a pointer, we know that it can't contain any
+                // pointers we need to retag, so we can stop recursion early.
+                // This optimization is crucial for ZSTs, because they can contain way more fields
+                // than we can ever visit.
+                if place.layout.is_sized() && place.layout.size < self.ecx.pointer_size() {
+                    return Ok(());
+                }
+
+                // Check the type of this value to see what to do with it (retag, or recurse).
+                match place.layout.ty.kind() {
+                    &ty::Ref(_, pointee, mutability) => {
+                        let new_perm =
+                            NewPermission::from_ref_ty(pointee, mutability, self.kind, self.ecx);
+                        self.retag_ptr_inplace(place, new_perm)?;
+                    }
+                    ty::RawPtr(_) => {
+                        // We definitely do *not* want to recurse into raw pointers -- wide raw
+                        // pointers have fields, and for dyn Trait pointees those can have reference
+                        // type!
+                        // We also do not want to reborrow them.
+                    }
+                    ty::Adt(adt, _) if adt.is_box() => {
+                        // Recurse for boxes, they require some tricky handling and will end up in `visit_box` above.
+                        // (Yes this means we technically also recursively retag the allocator itself
+                        // even if field retagging is not enabled. *shrug*)
+                        self.walk_value(place)?;
+                    }
+                    _ => {
+                        // Not a reference/pointer/box. Only recurse if configured appropriately.
+                        let recurse = match self.retag_fields {
+                            RetagFields::No => false,
+                            RetagFields::Yes => true,
+                            RetagFields::OnlyScalar => {
+                                // Matching `ArgAbi::new` at the time of writing, only fields of
+                                // `Scalar` and `ScalarPair` ABI are considered.
+                                matches!(place.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..))
+                            }
+                        };
+                        if recurse {
+                            self.walk_value(place)?;
+                        }
+                    }
+                }
+
+                Ok(())
+            }
+        }
+    }
+
+    /// After a stack frame got pushed, retag the return place so that we are sure
+    /// it does not alias with anything.
+    ///
+    /// This is a HACK because there is nothing in MIR that would make the retag
+    /// explicit. Also see <https://github.com/rust-lang/rust/issues/71117>.
+    fn tb_retag_return_place(&mut self) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        //this.debug_hint_location();
+        let return_place = &this.frame().return_place;
+        if return_place.layout.is_zst() {
+            // There may not be any memory here, nothing to do.
+            return Ok(());
+        }
+        // We need this to be in-memory to use tagged pointers.
+        let return_place = this.force_allocation(&return_place.clone())?;
+
+        // We have to turn the place into a pointer to use the existing code.
+        // (The pointer type does not matter, so we use a raw pointer.)
+        let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?;
+        let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout);
+        // Reborrow it. With protection! That is part of the point.
+        // FIXME: do we truly want a 2phase borrow here?
+        let new_perm = Some(NewPermission {
+            initial_state: Permission::new_unique_2phase(/*freeze*/ false),
+            perform_read_access: true,
+            protector: Some(ProtectorKind::StrongProtector),
+        });
+        let val = this.tb_retag_reference(&val, new_perm)?;
+        // And use reborrowed pointer for return place.
+        let return_place = this.ref_to_mplace(&val)?;
+        this.frame_mut().return_place = return_place.into();
+
+        Ok(())
+    }
+
+    /// Mark the given tag as exposed. It was found on a pointer with the given AllocId.
+    fn tb_expose_tag(&mut self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+
+        // Function pointers and dead objects don't have an alloc_extra so we ignore them.
+        // This is okay because accessing them is UB anyway, no need for any Tree Borrows checks.
+        // NOT using `get_alloc_extra_mut` since this might be a read-only allocation!
+        let (_size, _align, kind) = this.get_alloc_info(alloc_id);
+        match kind {
+            AllocKind::LiveData => {
+                // This should have alloc_extra data, but `get_alloc_extra` can still fail
+                // if converting this alloc_id from a global to a local one
+                // uncovers a non-supported `extern static`.
+                let alloc_extra = this.get_alloc_extra(alloc_id)?;
+                trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}");
+                alloc_extra.borrow_tracker_tb().borrow_mut().expose_tag(tag);
+            }
+            AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
+                // No tree borrows on these allocations.
+            }
+        }
+        Ok(())
+    }
+
+    /// Display the tree.
+    fn print_tree(&mut self, alloc_id: AllocId, show_unnamed: bool) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let alloc_extra = this.get_alloc_extra(alloc_id)?;
+        let tree_borrows = alloc_extra.borrow_tracker_tb().borrow();
+        let borrow_tracker = &this.machine.borrow_tracker.as_ref().unwrap().borrow();
+        tree_borrows.print_tree(&borrow_tracker.protected_tags, show_unnamed)
+    }
+
+    /// Give a name to the pointer, usually the name it has in the source code (for debugging).
+    /// The name given is `name` and the pointer that receives it is the `nth_parent`
+    /// of `ptr` (with 0 representing `ptr` itself)
+    fn tb_give_pointer_debug_name(
+        &mut self,
+        ptr: Pointer<Option<Provenance>>,
+        nth_parent: u8,
+        name: &str,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let (tag, alloc_id) = match ptr.provenance {
+            Some(Provenance::Concrete { tag, alloc_id }) => (tag, alloc_id),
+            _ => {
+                eprintln!("Can't give the name {name} to Wildcard pointer");
+                return Ok(());
+            }
+        };
+        let alloc_extra = this.get_alloc_extra(alloc_id)?;
+        let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut();
+        tree_borrows.give_pointer_debug_name(tag, nth_parent, name)
+    }
+}
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
new file mode 100644
index 00000000000..04b8e1df576
--- /dev/null
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -0,0 +1,307 @@
+use std::cmp::{Ordering, PartialOrd};
+use std::fmt;
+
+use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness;
+use crate::borrow_tracker::AccessKind;
+
+/// The activation states of a pointer
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum PermissionPriv {
+    /// represents: a local reference that has not yet been written to;
+    /// allows: child reads, foreign reads, foreign writes if type is freeze;
+    /// rejects: child writes (Active), foreign writes (Disabled, except if type is not freeze).
+    /// special case: behaves differently when protected to adhere more closely to noalias
+    Reserved { ty_is_freeze: bool },
+    /// represents: a unique pointer;
+    /// allows: child reads, child writes;
+    /// rejects: foreign reads (Frozen), foreign writes (Disabled).
+    Active,
+    /// represents: a shared pointer;
+    /// allows: all read accesses;
+    /// rejects child writes (UB), foreign writes (Disabled).
+    Frozen,
+    /// represents: a dead pointer;
+    /// allows: all foreign accesses;
+    /// rejects: all child accesses (UB).
+    Disabled,
+}
+use PermissionPriv::*;
+
+impl PartialOrd for PermissionPriv {
+    /// PermissionPriv is ordered as follows:
+    /// - Reserved(_) < Active < Frozen < Disabled;
+    /// - different kinds of `Reserved` (with or without interior mutability)
+    /// are incomparable to each other.
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        use Ordering::*;
+        Some(match (self, other) {
+            (a, b) if a == b => Equal,
+            (Disabled, _) => Greater,
+            (_, Disabled) => Less,
+            (Frozen, _) => Greater,
+            (_, Frozen) => Less,
+            (Active, _) => Greater,
+            (_, Active) => Less,
+            (Reserved { .. }, Reserved { .. }) => return None,
+        })
+    }
+}
+
+/// This module controls how each permission individually reacts to an access.
+/// Although these functions take `protected` as an argument, this is NOT because
+/// we check protector violations here, but because some permissions behave differently
+/// when protected.
+mod transition {
+    use super::*;
+    /// A child node was read-accessed: UB on Disabled, noop on the rest.
+    fn child_read(state: PermissionPriv, _protected: bool) -> Option<PermissionPriv> {
+        Some(match state {
+            Disabled => return None,
+            // The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read
+            // accesses, since the data is not being mutated. Hence the `{ .. }`
+            readable @ (Reserved { .. } | Active | Frozen) => readable,
+        })
+    }
+
+    /// A non-child node was read-accessed: noop on non-protected Reserved, advance to Frozen otherwise.
+    fn foreign_read(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> {
+        use Option::*;
+        Some(match state {
+            // The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read
+            // accesses, since the data is not being mutated. Hence the `{ .. }`
+            res @ Reserved { .. } if !protected => res,
+            Reserved { .. } => Frozen, // protected reserved
+            Active => Frozen,
+            non_writeable @ (Frozen | Disabled) => non_writeable,
+        })
+    }
+
+    /// A child node was write-accessed: `Reserved` must become `Active` to obtain
+    /// write permissions, `Frozen` and `Disabled` cannot obtain such permissions and produce UB.
+    fn child_write(state: PermissionPriv, _protected: bool) -> Option<PermissionPriv> {
+        Some(match state {
+            // A write always activates the 2-phase borrow, even with interior
+            // mutability
+            Reserved { .. } | Active => Active,
+            Frozen | Disabled => return None,
+        })
+    }
+
+    /// A non-child node was write-accessed: this makes everything `Disabled` except for
+    /// non-protected interior mutable `Reserved` which stay the same.
+    fn foreign_write(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> {
+        Some(match state {
+            cell @ Reserved { ty_is_freeze: false } if !protected => cell,
+            _ => Disabled,
+        })
+    }
+
+    /// Dispatch handler depending on the kind of access and its position.
+    pub(super) fn perform_access(
+        kind: AccessKind,
+        rel_pos: AccessRelatedness,
+        child: PermissionPriv,
+        protected: bool,
+    ) -> Option<PermissionPriv> {
+        match (kind, rel_pos.is_foreign()) {
+            (AccessKind::Write, true) => foreign_write(child, protected),
+            (AccessKind::Read, true) => foreign_read(child, protected),
+            (AccessKind::Write, false) => child_write(child, protected),
+            (AccessKind::Read, false) => child_read(child, protected),
+        }
+    }
+}
+
+impl PermissionPriv {
+    /// Determines whether a transition that occured is compatible with the presence
+    /// of a Protector. This is not included in the `transition` functions because
+    /// it would distract from the few places where the transition is modified
+    /// because of a protector, but not forbidden.
+    fn protector_allows_transition(self, new: Self) -> bool {
+        match (self, new) {
+            _ if self == new => true,
+            // It is always a protector violation to not be readable anymore
+            (_, Disabled) => false,
+            // In the case of a `Reserved` under a protector, both transitions
+            // `Reserved => Active` and `Reserved => Frozen` can legitimately occur.
+            // The first is standard (Child Write), the second is for Foreign Writes
+            // on protected Reserved where we must ensure that the pointer is not
+            // written to in the future.
+            (Reserved { .. }, Active) | (Reserved { .. }, Frozen) => true,
+            // This pointer should have stayed writeable for the whole function
+            (Active, Frozen) => false,
+            _ => unreachable!("Transition from {self:?} to {new:?} should never be possible"),
+        }
+    }
+}
+
+/// Public interface to the state machine that controls read-write permissions.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Permission(PermissionPriv);
+
+impl fmt::Display for Permission {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "{}",
+            match self.0 {
+                PermissionPriv::Reserved { .. } => "Reserved",
+                PermissionPriv::Active => "Active",
+                PermissionPriv::Frozen => "Frozen",
+                PermissionPriv::Disabled => "Disabled",
+            }
+        )
+    }
+}
+
+impl Permission {
+    /// Default initial permission of the root of a new tree.
+    pub fn new_root() -> Self {
+        Self(Active)
+    }
+
+    /// Default initial permission of a reborrowed mutable reference.
+    pub fn new_unique_2phase(ty_is_freeze: bool) -> Self {
+        Self(Reserved { ty_is_freeze })
+    }
+
+    /// Default initial permission of a reborrowed shared reference
+    pub fn new_frozen() -> Self {
+        Self(Frozen)
+    }
+
+    /// Pretty-printing. Needs to be here and not in diagnostics.rs
+    /// because `Self` is private.
+    pub fn short_name(self) -> &'static str {
+        // Make sure there are all of the same length as each other
+        // and also as `diagnostics::DisplayFmtPermission.uninit` otherwise
+        // alignment will be incorrect.
+        match self.0 {
+            Reserved { ty_is_freeze: true } => "Res",
+            Reserved { ty_is_freeze: false } => "Re*",
+            Active => "Act",
+            Frozen => "Frz",
+            Disabled => "Dis",
+        }
+    }
+
+    /// Check that there are no complaints from a possible protector.
+    ///
+    /// Note: this is not in charge of checking that there *is* a protector,
+    /// it should be used as
+    /// ```
+    /// let no_protector_error = if is_protected(tag) {
+    ///     old_perm.protector_allows_transition(new_perm)
+    /// };
+    /// ```
+    pub fn protector_allows_transition(self, new: Self) -> bool {
+        self.0.protector_allows_transition(new.0)
+    }
+
+    /// Apply the transition to the inner PermissionPriv.
+    pub fn perform_access(
+        kind: AccessKind,
+        rel_pos: AccessRelatedness,
+        old_perm: Self,
+        protected: bool,
+    ) -> Option<Self> {
+        let old_state = old_perm.0;
+        transition::perform_access(kind, rel_pos, old_state, protected).map(Self)
+    }
+}
+
+#[cfg(test)]
+mod propagation_optimization_checks {
+    pub use super::*;
+
+    mod util {
+        pub use super::*;
+        impl PermissionPriv {
+            /// Enumerate all states
+            pub fn all() -> impl Iterator<Item = PermissionPriv> {
+                vec![
+                    Active,
+                    Reserved { ty_is_freeze: true },
+                    Reserved { ty_is_freeze: false },
+                    Frozen,
+                    Disabled,
+                ]
+                .into_iter()
+            }
+        }
+
+        impl AccessKind {
+            /// Enumerate all AccessKind.
+            pub fn all() -> impl Iterator<Item = AccessKind> {
+                use AccessKind::*;
+                [Read, Write].into_iter()
+            }
+        }
+
+        impl AccessRelatedness {
+            /// Enumerate all relative positions
+            pub fn all() -> impl Iterator<Item = AccessRelatedness> {
+                use AccessRelatedness::*;
+                [This, StrictChildAccess, AncestorAccess, DistantAccess].into_iter()
+            }
+        }
+    }
+
+    #[test]
+    // For any kind of access, if we do it twice the second should be a no-op.
+    // Even if the protector has disappeared.
+    fn all_transitions_idempotent() {
+        use transition::*;
+        for old in PermissionPriv::all() {
+            for (old_protected, new_protected) in [(true, true), (true, false), (false, false)] {
+                for access in AccessKind::all() {
+                    for rel_pos in AccessRelatedness::all() {
+                        if let Some(new) = perform_access(access, rel_pos, old, old_protected) {
+                            assert_eq!(
+                                new,
+                                perform_access(access, rel_pos, new, new_protected).unwrap()
+                            );
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    #[test]
+    fn foreign_read_is_noop_after_write() {
+        use transition::*;
+        let old_access = AccessKind::Write;
+        let new_access = AccessKind::Read;
+        for old in PermissionPriv::all() {
+            for (old_protected, new_protected) in [(true, true), (true, false), (false, false)] {
+                for rel_pos in AccessRelatedness::all().filter(|rel| rel.is_foreign()) {
+                    if let Some(new) = perform_access(old_access, rel_pos, old, old_protected) {
+                        assert_eq!(
+                            new,
+                            perform_access(new_access, rel_pos, new, new_protected).unwrap()
+                        );
+                    }
+                }
+            }
+        }
+    }
+
+    #[test]
+    // Check that all transitions are consistent with the order on PermissionPriv,
+    // i.e. Reserved -> Active -> Frozen -> Disabled
+    fn access_transitions_progress_increasing() {
+        use transition::*;
+        for old in PermissionPriv::all() {
+            for protected in [true, false] {
+                for access in AccessKind::all() {
+                    for rel_pos in AccessRelatedness::all() {
+                        if let Some(new) = perform_access(access, rel_pos, old, protected) {
+                            assert!(old <= new);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
new file mode 100644
index 00000000000..86416a0eb1b
--- /dev/null
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
@@ -0,0 +1,554 @@
+//! In this file we handle the "Tree" part of Tree Borrows, i.e. all tree
+//! traversal functions, optimizations to trim branches, and keeping track of
+//! the relative position of the access to each node being updated. This of course
+//! also includes the definition of the tree structure.
+//!
+//! Functions here manipulate permissions but are oblivious to them: as
+//! the internals of `Permission` are private, the update process is a black
+//! box. All we need to know here are
+//! - the fact that updates depend only on the old state, the status of protectors,
+//!   and the relative position of the access;
+//! - idempotency properties asserted in `perms.rs` (for optimizations)
+
+use smallvec::SmallVec;
+
+use rustc_const_eval::interpret::InterpResult;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_target::abi::Size;
+
+use crate::borrow_tracker::tree_borrows::{
+    diagnostics::{NodeDebugInfo, TbError, TransitionError},
+    unimap::{UniEntry, UniIndex, UniKeyMap, UniValMap},
+    Permission,
+};
+use crate::borrow_tracker::{AccessKind, GlobalState, ProtectorKind};
+use crate::*;
+
+/// Data for a single *location*.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(super) struct LocationState {
+    /// This pointer's current permission
+    permission: Permission,
+    /// A location is initialized when it is child accessed for the first time,
+    /// and it then stays initialized forever.
+    /// Before initialization we still apply some preemptive transitions on
+    /// `permission` to know what to do in case it ever gets initialized,
+    /// but these can never cause any immediate UB. There can however be UB
+    /// the moment we attempt to initalize (i.e. child-access) because some
+    /// foreign access done between the creation and the initialization is
+    /// incompatible with child accesses.
+    initialized: bool,
+    /// Strongest foreign access whose effects have already been applied to
+    /// this node and all its children since the last child access.
+    /// This is `None` if the most recent access is a child access,
+    /// `Some(Write)` if at least one foreign write access has been applied
+    /// since the previous child access, and `Some(Read)` if at least one
+    /// foreign read and no foreign write have occurred since the last child access.
+    latest_foreign_access: Option<AccessKind>,
+}
+
+impl LocationState {
+    /// Default initial state has never been accessed and has been subjected to no
+    /// foreign access.
+    fn new(permission: Permission) -> Self {
+        Self { permission, initialized: false, latest_foreign_access: None }
+    }
+
+    /// Record that this location was accessed through a child pointer by
+    /// marking it as initialized
+    fn with_access(mut self) -> Self {
+        self.initialized = true;
+        self
+    }
+
+    pub fn is_initialized(&self) -> bool {
+        self.initialized
+    }
+
+    pub fn permission(&self) -> Permission {
+        self.permission
+    }
+}
+
+/// Tree structure with both parents and children since we want to be
+/// able to traverse the tree efficiently in both directions.
+#[derive(Clone, Debug)]
+pub struct Tree {
+    /// Mapping from tags to keys. The key obtained can then be used in
+    /// any of the `UniValMap` relative to this allocation, i.e. both the
+    /// `nodes` and `rperms` of the same `Tree`.
+    /// The parent-child relationship in `Node` is encoded in terms of these same
+    /// keys, so traversing the entire tree needs exactly one access to
+    /// `tag_mapping`.
+    pub(super) tag_mapping: UniKeyMap<BorTag>,
+    /// All nodes of this tree.
+    pub(super) nodes: UniValMap<Node>,
+    /// Maps a tag and a location to a perm, with possible lazy
+    /// initialization.
+    ///
+    /// NOTE: not all tags registered in `nodes` are necessarily in all
+    /// ranges of `rperms`, because `rperms` is in part lazily initialized.
+    /// Just because `nodes.get(key)` is `Some(_)` does not mean you can safely
+    /// `unwrap` any `perm.get(key)`.
+    ///
+    /// We do uphold the fact that `keys(perms)` is a subset of `keys(nodes)`
+    pub(super) rperms: RangeMap<UniValMap<LocationState>>,
+    /// The index of the root node.
+    pub(super) root: UniIndex,
+}
+
+/// A node in the borrow tree. Each node is uniquely identified by a tag via
+/// the `nodes` map of `Tree`.
+#[derive(Clone, Debug)]
+pub(super) struct Node {
+    /// The tag of this node.
+    pub tag: BorTag,
+    /// All tags except the root have a parent tag.
+    pub parent: Option<UniIndex>,
+    /// If the pointer was reborrowed, it has children.
+    // FIXME: bench to compare this to FxHashSet and to other SmallVec sizes
+    pub children: SmallVec<[UniIndex; 4]>,
+    /// Either `Reserved` or `Frozen`, the permission this tag will be lazily initialized
+    /// to on the first access.
+    default_initial_perm: Permission,
+    /// Some extra information useful only for debugging purposes
+    pub debug_info: NodeDebugInfo,
+}
+
+/// Data given to the transition function
+struct NodeAppArgs<'node> {
+    /// Node on which the transition is currently being applied
+    node: &'node Node,
+    /// Mutable access to its permissions
+    perm: UniEntry<'node, LocationState>,
+    /// Relative position of the access
+    rel_pos: AccessRelatedness,
+}
+/// Data given to the error handler
+struct ErrHandlerArgs<'node, InErr> {
+    /// Kind of error that occurred
+    error_kind: InErr,
+    /// Tag that triggered the error (not the tag that was accessed,
+    /// rather the parent tag that had insufficient permissions or the
+    /// non-parent tag that had a protector).
+    faulty_tag: &'node NodeDebugInfo,
+}
+/// Internal contents of `Tree` with the minimum of mutable access for
+/// the purposes of the tree traversal functions: the permissions (`perms`) can be
+/// updated but not the tree structure (`tag_mapping` and `nodes`)
+struct TreeVisitor<'tree> {
+    tag_mapping: &'tree UniKeyMap<BorTag>,
+    nodes: &'tree UniValMap<Node>,
+    perms: &'tree mut UniValMap<LocationState>,
+}
+
+/// Whether to continue exploring the children recursively or not.
+enum ContinueTraversal {
+    Recurse,
+    SkipChildren,
+}
+
+impl<'tree> TreeVisitor<'tree> {
+    // Applies `f_propagate` to every vertex of the tree top-down in the following order: first
+    // all ancestors of `start`, then `start` itself, then children of `start`, then the rest.
+    // This ensures that errors are triggered in the following order
+    // - first invalid accesses with insufficient permissions, closest to the root first,
+    // - then protector violations, closest to `start` first.
+    //
+    // `f_propagate` should follow the following format: for a given `Node` it updates its
+    // `Permission` depending on the position relative to `start` (given by an
+    // `AccessRelatedness`).
+    // It outputs whether the tree traversal for this subree should continue or not.
+    fn traverse_parents_this_children_others<InnErr, OutErr>(
+        mut self,
+        start: BorTag,
+        f_propagate: impl Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>,
+        err_builder: impl Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr,
+    ) -> Result<(), OutErr>
+where {
+        struct TreeVisitAux<NodeApp, ErrHandler> {
+            f_propagate: NodeApp,
+            err_builder: ErrHandler,
+            stack: Vec<(UniIndex, AccessRelatedness)>,
+        }
+        impl<NodeApp, InnErr, OutErr, ErrHandler> TreeVisitAux<NodeApp, ErrHandler>
+        where
+            NodeApp: Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>,
+            ErrHandler: Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr,
+        {
+            fn pop(&mut self) -> Option<(UniIndex, AccessRelatedness)> {
+                self.stack.pop()
+            }
+
+            /// Apply the function to the current `tag`, and push its children
+            /// to the stack of future tags to visit.
+            fn exec_and_visit(
+                &mut self,
+                this: &mut TreeVisitor<'_>,
+                tag: UniIndex,
+                exclude: Option<UniIndex>,
+                rel_pos: AccessRelatedness,
+            ) -> Result<(), OutErr> {
+                // 1. apply the propagation function
+                let node = this.nodes.get(tag).unwrap();
+                let recurse =
+                    (self.f_propagate)(NodeAppArgs { node, perm: this.perms.entry(tag), rel_pos })
+                        .map_err(|error_kind| {
+                            (self.err_builder)(ErrHandlerArgs {
+                                error_kind,
+                                faulty_tag: &node.debug_info,
+                            })
+                        })?;
+                // 2. add the children to the stack for future traversal
+                if matches!(recurse, ContinueTraversal::Recurse) {
+                    let child_rel = rel_pos.for_child();
+                    for &child in node.children.iter() {
+                        // some child might be excluded from here and handled separately
+                        if Some(child) != exclude {
+                            self.stack.push((child, child_rel));
+                        }
+                    }
+                }
+                Ok(())
+            }
+        }
+
+        let start_idx = self.tag_mapping.get(&start).unwrap();
+        let mut stack = TreeVisitAux { f_propagate, err_builder, stack: Vec::new() };
+        {
+            let mut path_ascend = Vec::new();
+            // First climb to the root while recording the path
+            let mut curr = start_idx;
+            while let Some(ancestor) = self.nodes.get(curr).unwrap().parent {
+                path_ascend.push((ancestor, curr));
+                curr = ancestor;
+            }
+            // Then descend:
+            // - execute f_propagate on each node
+            // - record children in visit
+            while let Some((ancestor, next_in_path)) = path_ascend.pop() {
+                // Explore ancestors in descending order.
+                // `next_in_path` is excluded from the recursion because it
+                // will be the `ancestor` of the next iteration.
+                // It also needs a different `AccessRelatedness` than the other
+                // children of `ancestor`.
+                stack.exec_and_visit(
+                    &mut self,
+                    ancestor,
+                    Some(next_in_path),
+                    AccessRelatedness::StrictChildAccess,
+                )?;
+            }
+        };
+        // All (potentially zero) ancestors have been explored, call f_propagate on start
+        stack.exec_and_visit(&mut self, start_idx, None, AccessRelatedness::This)?;
+        // up to this point we have never popped from `stack`, hence if the
+        // path to the root is `root = p(n) <- p(n-1)... <- p(1) <- p(0) = start`
+        // then now `stack` contains
+        // `[<children(p(n)) except p(n-1)> ... <children(p(1)) except p(0)> <children(p(0))>]`,
+        // all of which are for now unexplored.
+        // This is the starting point of a standard DFS which will thus
+        // explore all non-ancestors of `start` in the following order:
+        // - all descendants of `start`;
+        // - then the unexplored descendants of `parent(start)`;
+        // ...
+        // - until finally the unexplored descendants of `root`.
+        while let Some((tag, rel_pos)) = stack.pop() {
+            stack.exec_and_visit(&mut self, tag, None, rel_pos)?;
+        }
+        Ok(())
+    }
+}
+
+impl Tree {
+    /// Create a new tree, with only a root pointer.
+    pub fn new(root_tag: BorTag, size: Size) -> Self {
+        let root_perm = Permission::new_root();
+        let mut tag_mapping = UniKeyMap::default();
+        let root_idx = tag_mapping.insert(root_tag);
+        let nodes = {
+            let mut nodes = UniValMap::<Node>::default();
+            nodes.insert(
+                root_idx,
+                Node {
+                    tag: root_tag,
+                    parent: None,
+                    children: SmallVec::default(),
+                    default_initial_perm: root_perm,
+                    debug_info: NodeDebugInfo::new(root_tag),
+                },
+            );
+            nodes
+        };
+        let rperms = {
+            let mut perms = UniValMap::default();
+            perms.insert(root_idx, LocationState::new(root_perm).with_access());
+            RangeMap::new(size, perms)
+        };
+        Self { root: root_idx, nodes, rperms, tag_mapping }
+    }
+}
+
+impl<'tcx> Tree {
+    /// Insert a new tag in the tree
+    pub fn new_child(
+        &mut self,
+        parent_tag: BorTag,
+        new_tag: BorTag,
+        default_initial_perm: Permission,
+        range: AllocRange,
+    ) -> InterpResult<'tcx> {
+        assert!(!self.tag_mapping.contains_key(&new_tag));
+        let idx = self.tag_mapping.insert(new_tag);
+        let parent_idx = self.tag_mapping.get(&parent_tag).unwrap();
+        // Create the node
+        self.nodes.insert(
+            idx,
+            Node {
+                tag: new_tag,
+                parent: Some(parent_idx),
+                children: SmallVec::default(),
+                default_initial_perm,
+                debug_info: NodeDebugInfo::new(new_tag),
+            },
+        );
+        // Register new_tag as a child of parent_tag
+        self.nodes.get_mut(parent_idx).unwrap().children.push(idx);
+        // Initialize perms
+        let perm = LocationState::new(default_initial_perm).with_access();
+        for (_range, perms) in self.rperms.iter_mut(range.start, range.size) {
+            perms.insert(idx, perm);
+        }
+        Ok(())
+    }
+
+    /// Deallocation requires
+    /// - a pointer that permits write accesses
+    /// - the absence of Strong Protectors anywhere in the allocation
+    pub fn dealloc(
+        &mut self,
+        tag: BorTag,
+        range: AllocRange,
+        global: &GlobalState,
+    ) -> InterpResult<'tcx> {
+        self.perform_access(AccessKind::Write, tag, range, global)?;
+        let access_info = &self.nodes.get(self.tag_mapping.get(&tag).unwrap()).unwrap().debug_info;
+        for (_range, perms) in self.rperms.iter_mut(range.start, range.size) {
+            TreeVisitor { nodes: &self.nodes, tag_mapping: &self.tag_mapping, perms }
+                .traverse_parents_this_children_others(
+                    tag,
+                    |args: NodeAppArgs<'_>| -> Result<ContinueTraversal, TransitionError> {
+                        let NodeAppArgs { node, .. } = args;
+                        if global.borrow().protected_tags.get(&node.tag)
+                            == Some(&ProtectorKind::StrongProtector)
+                        {
+                            Err(TransitionError::ProtectedDealloc)
+                        } else {
+                            Ok(ContinueTraversal::Recurse)
+                        }
+                    },
+                    |args: ErrHandlerArgs<'_, TransitionError>| -> InterpErrorInfo<'tcx> {
+                        let ErrHandlerArgs { error_kind, faulty_tag } = args;
+                        TbError {
+                            faulty_tag,
+                            access_kind: AccessKind::Write,
+                            error_kind,
+                            tag_of_access: access_info,
+                        }
+                        .build()
+                    },
+                )?;
+        }
+        Ok(())
+    }
+
+    /// Maps the following propagation procedure to each range:
+    /// - initialize if needed;
+    /// - compute new state after transition;
+    /// - check that there is no protector that would forbid this;
+    /// - record this specific location as accessed.
+    pub fn perform_access(
+        &mut self,
+        access_kind: AccessKind,
+        tag: BorTag,
+        range: AllocRange,
+        global: &GlobalState,
+    ) -> InterpResult<'tcx> {
+        let access_info = &self.nodes.get(self.tag_mapping.get(&tag).unwrap()).unwrap().debug_info;
+        for (_range, perms) in self.rperms.iter_mut(range.start, range.size) {
+            TreeVisitor { nodes: &self.nodes, tag_mapping: &self.tag_mapping, perms }
+                .traverse_parents_this_children_others(
+                    tag,
+                    |args: NodeAppArgs<'_>| -> Result<ContinueTraversal, TransitionError> {
+                        let NodeAppArgs { node, mut perm, rel_pos } = args;
+
+                        let old_state =
+                            perm.or_insert_with(|| LocationState::new(node.default_initial_perm));
+
+                        // Optimize the tree traversal.
+                        // The optimization here consists of observing thanks to the tests
+                        // `foreign_read_is_noop_after_write` and `all_transitions_idempotent`
+                        // that if we apply twice in a row the effects of a foreign access
+                        // we can skip some branches.
+                        // "two foreign accesses in a row" occurs when `perm.latest_foreign_access` is `Some(_)`
+                        // AND the `rel_pos` of the current access corresponds to a foreign access.
+                        if rel_pos.is_foreign() {
+                            let new_access_noop =
+                                match (old_state.latest_foreign_access, access_kind) {
+                                    // Previously applied transition makes the new one a guaranteed
+                                    // noop in the two following cases:
+                                    // (1) justified by `foreign_read_is_noop_after_write`
+                                    (Some(AccessKind::Write), AccessKind::Read) => true,
+                                    // (2) justified by `all_transitions_idempotent`
+                                    (Some(old), new) if old == new => true,
+                                    // In all other cases there has been a recent enough
+                                    // child access that the effects of the new foreign access
+                                    // need to be applied to this subtree.
+                                    _ => false,
+                                };
+                            if new_access_noop {
+                                // Abort traversal if the new transition is indeed guaranteed
+                                // to be noop.
+                                return Ok(ContinueTraversal::SkipChildren);
+                            } else {
+                                // Otherwise propagate this time, and also record the
+                                // access that just occurred so that we can skip the propagation
+                                // next time.
+                                old_state.latest_foreign_access = Some(access_kind);
+                            }
+                        } else {
+                            // A child access occurred, this breaks the streak of "two foreign
+                            // accesses in a row" and we reset this field.
+                            old_state.latest_foreign_access = None;
+                        }
+
+                        let old_perm = old_state.permission;
+                        let protected = global.borrow().protected_tags.contains_key(&node.tag);
+                        let new_perm =
+                            Permission::perform_access(access_kind, rel_pos, old_perm, protected)
+                                .ok_or(TransitionError::ChildAccessForbidden(old_perm))?;
+                        if protected
+                            // Can't trigger Protector on uninitialized locations
+                            && old_state.initialized
+                            && !old_perm.protector_allows_transition(new_perm)
+                        {
+                            return Err(TransitionError::ProtectedTransition(old_perm, new_perm));
+                        }
+                        old_state.permission = new_perm;
+                        old_state.initialized |= !rel_pos.is_foreign();
+                        Ok(ContinueTraversal::Recurse)
+                    },
+                    |args: ErrHandlerArgs<'_, TransitionError>| -> InterpErrorInfo<'tcx> {
+                        let ErrHandlerArgs { error_kind, faulty_tag } = args;
+                        TbError { faulty_tag, access_kind, error_kind, tag_of_access: access_info }
+                            .build()
+                    },
+                )?;
+        }
+        Ok(())
+    }
+}
+
+/// Integration with the BorTag garbage collector
+impl Tree {
+    pub fn remove_unreachable_tags(&mut self, live_tags: &FxHashSet<BorTag>) {
+        assert!(self.keep_only_needed(self.root, live_tags)); // root can't be removed
+    }
+
+    /// Traverses the entire tree looking for useless tags.
+    /// Returns true iff the tag it was called on is still live or has live children,
+    /// and removes from the tree all tags that have no live children.
+    ///
+    /// NOTE: This leaves in the middle of the tree tags that are unreachable but have
+    /// reachable children. There is a potential for compacting the tree by reassigning
+    /// children of dead tags to the nearest live parent, but it must be done with care
+    /// not to remove UB.
+    ///
+    /// Example: Consider the tree `root - parent - child`, with `parent: Frozen` and
+    /// `child: Reserved`. This tree can exist. If we blindly delete `parent` and reassign
+    /// `child` to be a direct child of `root` then Writes to `child` are now permitted
+    /// whereas they were not when `parent` was still there.
+    fn keep_only_needed(&mut self, idx: UniIndex, live: &FxHashSet<BorTag>) -> bool {
+        let node = self.nodes.get(idx).unwrap();
+        // FIXME: this function does a lot of cloning, a 2-pass approach is possibly
+        // more efficient. It could consist of
+        // 1. traverse the Tree, collect all useless tags in a Vec
+        // 2. traverse the Vec, remove all tags previously selected
+        // Bench it.
+        let children: SmallVec<_> = node
+            .children
+            .clone()
+            .into_iter()
+            .filter(|child| self.keep_only_needed(*child, live))
+            .collect();
+        let no_children = children.is_empty();
+        let node = self.nodes.get_mut(idx).unwrap();
+        node.children = children;
+        if !live.contains(&node.tag) && no_children {
+            // All of the children and this node are unreachable, delete this tag
+            // from the tree (the children have already been deleted by recursive
+            // calls).
+            // Due to the API of UniMap we must absolutely call
+            // `UniValMap::remove` for the key of this tag on *all* maps that used it
+            // (which are `self.nodes` and every range of `self.rperms`)
+            // before we can safely apply `UniValMap::forget` to truly remove
+            // the tag from the mapping.
+            let tag = node.tag;
+            self.nodes.remove(idx);
+            for perms in self.rperms.iter_mut_all() {
+                perms.remove(idx);
+            }
+            self.tag_mapping.remove(&tag);
+            // The tag has been deleted, inform the caller
+            false
+        } else {
+            // The tag is still live or has live children, it must be kept
+            true
+        }
+    }
+}
+
+impl VisitTags for Tree {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
+        // To ensure that the root never gets removed, we visit it
+        // (the `root` node of `Tree` is not an `Option<_>`)
+        visit(self.nodes.get(self.root).unwrap().tag)
+    }
+}
+
+/// Relative position of the access
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum AccessRelatedness {
+    /// The accessed pointer is the current one
+    This,
+    /// The accessed pointer is a (transitive) child of the current one.
+    // Current pointer is excluded (unlike in some other places of this module
+    // where "child" is inclusive).
+    StrictChildAccess,
+    /// The accessed pointer is a (transitive) parent of the current one.
+    // Current pointer is excluded.
+    AncestorAccess,
+    /// The accessed pointer is neither of the above.
+    // It's a cousin/uncle/etc., something in a side branch.
+    // FIXME: find a better name ?
+    DistantAccess,
+}
+
+impl AccessRelatedness {
+    /// Check that access is either Ancestor or Distant, i.e. not
+    /// a transitive child (initial pointer included).
+    pub fn is_foreign(self) -> bool {
+        matches!(self, AccessRelatedness::AncestorAccess | AccessRelatedness::DistantAccess)
+    }
+
+    /// Given the AccessRelatedness for the parent node, compute the AccessRelatedness
+    /// for the child node. This function assumes that we propagate away from the initial
+    /// access.
+    pub fn for_child(self) -> Self {
+        use AccessRelatedness::*;
+        match self {
+            AncestorAccess | This => AncestorAccess,
+            StrictChildAccess | DistantAccess => DistantAccess,
+        }
+    }
+}
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
new file mode 100644
index 00000000000..c1d452ca89e
--- /dev/null
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
@@ -0,0 +1,304 @@
+//! This module implements the `UniMap`, which is a way to get efficient mappings
+//! optimized for the setting of `tree_borrows/tree.rs`.
+//!
+//! A `UniKeyMap<K>` is a (slow) mapping from `K` to `UniIndex`,
+//! and `UniValMap<V>` is a (fast) mapping from `UniIndex` to `V`.
+//! Thus a pair `(UniKeyMap<K>, UniValMap<V>)` acts as a virtual `HashMap<K, V>`.
+//!
+//! Because of the asymmetry in access time, the use-case for `UniMap` is the following:
+//! a tuple `(UniKeyMap<K>, Vec<UniValMap<V>>)` is much more efficient than
+//! the equivalent `Vec<HashMap<K, V>>` it represents if all maps have similar
+//! sets of keys.
+
+#![allow(dead_code)]
+
+use std::hash::Hash;
+
+use rustc_data_structures::fx::FxHashMap;
+
+/// Intermediate key between a UniKeyMap and a UniValMap.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct UniIndex {
+    idx: u32,
+}
+
+/// From K to UniIndex
+#[derive(Debug, Clone, Default)]
+pub struct UniKeyMap<K> {
+    /// Underlying map that does all the hard work.
+    /// Key invariant: the contents of `deassigned` are disjoint from the
+    /// keys of `mapping`, and together they form the set of contiguous integers
+    /// `0 .. (mapping.len() + deassigned.len())`.
+    mapping: FxHashMap<K, u32>,
+    /// Indexes that can be reused: memory gain when the map gets sparse
+    /// due to many deletions.
+    deassigned: Vec<u32>,
+}
+
+/// From UniIndex to V
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct UniValMap<V> {
+    /// The mapping data. Thanks to Vec we get both fast accesses, and
+    /// a memory-optimal representation if there are few deletions.
+    data: Vec<Option<V>>,
+}
+
+impl<V> Default for UniValMap<V> {
+    fn default() -> Self {
+        Self { data: Vec::default() }
+    }
+}
+
+impl<K> UniKeyMap<K>
+where
+    K: Hash + Eq,
+{
+    /// How many keys/index pairs are currently active.
+    pub fn len(&self) -> usize {
+        self.mapping.len()
+    }
+
+    /// Whether this key has an associated index or not.
+    pub fn contains_key(&self, key: &K) -> bool {
+        self.mapping.contains_key(key)
+    }
+
+    /// Assign this key to a new index. Panics if the key is already assigned,
+    /// use `get_or_insert` for a version that instead returns the existing
+    /// assignment.
+    #[track_caller]
+    pub fn insert(&mut self, key: K) -> UniIndex {
+        // We want an unused index. First we attempt to find one from `deassigned`,
+        // and if `deassigned` is empty we generate a fresh index.
+        let idx = self.deassigned.pop().unwrap_or_else(|| {
+            // `deassigned` is empty, so all keys in use are already in `mapping`.
+            // The next available key is `mapping.len()`.
+            self.mapping.len().try_into().expect("UniMap ran out of useable keys")
+        });
+        if self.mapping.insert(key, idx).is_some() {
+            panic!(
+                "This key is already assigned to a different index; either use `get_or_insert` instead if you care about this data, or first call `remove` to undo the preexisting assignment."
+            );
+        };
+        UniIndex { idx }
+    }
+
+    /// If it exists, the index this key maps to.
+    pub fn get(&self, key: &K) -> Option<UniIndex> {
+        self.mapping.get(key).map(|&idx| UniIndex { idx })
+    }
+
+    /// Either get a previously existing entry, or create a new one if it
+    /// is not yet present.
+    pub fn get_or_insert(&mut self, key: K) -> UniIndex {
+        self.get(&key).unwrap_or_else(|| self.insert(key))
+    }
+
+    /// Return whatever index this key was using to the deassigned pool.
+    ///
+    /// Note: calling this function can be dangerous. If the index still exists
+    /// somewhere in a `UniValMap` and is reassigned by the `UniKeyMap` then
+    /// it will inherit the old value of a completely unrelated key.
+    /// If you `UniKeyMap::remove` a key you should make sure to also `UniValMap::remove`
+    /// the associated `UniIndex` from ALL `UniValMap`s.
+    ///
+    /// Example of such behavior:
+    /// ```
+    /// let mut keymap = UniKeyMap::<char>::default();
+    /// let mut valmap = UniValMap::<char>::default();
+    /// // Insert 'a' -> _ -> 'A'
+    /// let idx_a = keymap.insert('a');
+    /// valmap.insert(idx_a, 'A');
+    /// // Remove 'a' -> _, but forget to remove _ -> 'A'
+    /// keymap.remove(&'a');
+    /// // valmap.remove(idx_a); // If we uncomment this line the issue is fixed
+    /// // Insert 'b' -> _
+    /// let idx_b = keymap.insert('b');
+    /// let val_b = valmap.get(idx_b);
+    /// assert_eq!(val_b, Some('A')); // Oh no
+    /// // assert_eq!(val_b, None); // This is what we would have expected
+    /// ```
+    pub fn remove(&mut self, key: &K) {
+        if let Some(idx) = self.mapping.remove(key) {
+            self.deassigned.push(idx);
+        }
+    }
+}
+
+impl<V> UniValMap<V> {
+    /// Whether this index has an associated value.
+    pub fn contains_idx(&self, idx: UniIndex) -> bool {
+        self.data.get(idx.idx as usize).and_then(Option::as_ref).is_some()
+    }
+
+    /// Reserve enough space to insert the value at the right index.
+    fn extend_to_length(&mut self, len: usize) {
+        if len > self.data.len() {
+            let nb = len - self.data.len();
+            self.data.reserve(nb);
+            for _ in 0..nb {
+                self.data.push(None);
+            }
+        }
+    }
+
+    /// Assign a value to the index. Permanently overwrites any previous value.
+    pub fn insert(&mut self, idx: UniIndex, val: V) {
+        self.extend_to_length(idx.idx as usize + 1);
+        self.data[idx.idx as usize] = Some(val)
+    }
+
+    /// Get the value at this index, if it exists.
+    pub fn get(&self, idx: UniIndex) -> Option<&V> {
+        self.data.get(idx.idx as usize).and_then(Option::as_ref)
+    }
+
+    /// Get the value at this index mutably, if it exists.
+    pub fn get_mut(&mut self, idx: UniIndex) -> Option<&mut V> {
+        self.data.get_mut(idx.idx as usize).and_then(Option::as_mut)
+    }
+
+    /// Delete any value associated with this index. Ok even if the index
+    /// has no associated value.
+    pub fn remove(&mut self, idx: UniIndex) {
+        if idx.idx as usize >= self.data.len() {
+            return;
+        }
+        self.data[idx.idx as usize] = None;
+    }
+}
+
+/// An access to a single value of the map.
+pub struct UniEntry<'a, V> {
+    inner: &'a mut Option<V>,
+}
+
+impl<'a, V> UniValMap<V> {
+    /// Get a wrapper around a mutable access to the value corresponding to `idx`.
+    pub fn entry(&'a mut self, idx: UniIndex) -> UniEntry<'a, V> {
+        self.extend_to_length(idx.idx as usize + 1);
+        UniEntry { inner: &mut self.data[idx.idx as usize] }
+    }
+}
+
+impl<'a, V> UniEntry<'a, V> {
+    /// Insert in the map and get the value.
+    pub fn or_insert_with<F>(&mut self, default: F) -> &mut V
+    where
+        F: FnOnce() -> V,
+    {
+        if self.inner.is_none() {
+            *self.inner = Some(default());
+        }
+        self.inner.as_mut().unwrap()
+    }
+}
+
+mod tests {
+    use super::*;
+
+    #[test]
+    fn extend_to_length() {
+        let mut km = UniValMap::<char>::default();
+        km.extend_to_length(10);
+        assert!(km.data.len() == 10);
+        km.extend_to_length(0);
+        assert!(km.data.len() == 10);
+        km.extend_to_length(10);
+        assert!(km.data.len() == 10);
+        km.extend_to_length(11);
+        assert!(km.data.len() == 11);
+    }
+
+    #[derive(Default)]
+    struct MapWitness<K, V> {
+        key: UniKeyMap<K>,
+        val: UniValMap<V>,
+        map: FxHashMap<K, V>,
+    }
+
+    impl<K, V> MapWitness<K, V>
+    where
+        K: Copy + Hash + Eq,
+        V: Copy + Eq + std::fmt::Debug,
+    {
+        fn insert(&mut self, k: K, v: V) {
+            // UniMap
+            let i = self.key.get_or_insert(k);
+            self.val.insert(i, v);
+            // HashMap
+            self.map.insert(k, v);
+            // Consistency: nothing to check
+        }
+
+        fn get(&self, k: &K) {
+            // UniMap
+            let v1 = self.key.get(k).and_then(|i| self.val.get(i));
+            // HashMap
+            let v2 = self.map.get(k);
+            // Consistency
+            assert_eq!(v1, v2);
+        }
+
+        fn get_mut(&mut self, k: &K) {
+            // UniMap
+            let v1 = self.key.get(k).and_then(|i| self.val.get_mut(i));
+            // HashMap
+            let v2 = self.map.get_mut(k);
+            // Consistency
+            assert_eq!(v1, v2);
+        }
+        fn remove(&mut self, k: &K) {
+            // UniMap
+            if let Some(i) = self.key.get(k) {
+                self.val.remove(i);
+            }
+            self.key.remove(k);
+            // HashMap
+            self.map.remove(k);
+            // Consistency: nothing to check
+        }
+    }
+
+    #[test]
+    fn consistency_small() {
+        let mut m = MapWitness::<u64, char>::default();
+        m.insert(1, 'a');
+        m.insert(2, 'b');
+        m.get(&1);
+        m.get_mut(&2);
+        m.remove(&2);
+        m.insert(1, 'c');
+        m.get(&1);
+        m.insert(3, 'd');
+        m.insert(4, 'e');
+        m.insert(4, 'f');
+        m.get(&2);
+        m.get(&3);
+        m.get(&4);
+        m.get(&5);
+        m.remove(&100);
+        m.get_mut(&100);
+        m.get(&100);
+    }
+
+    #[test]
+    fn consistency_large() {
+        use std::collections::hash_map::DefaultHasher;
+        use std::hash::{Hash, Hasher};
+        let mut hasher = DefaultHasher::new();
+        let mut map = MapWitness::<u64, u64>::default();
+        for i in 0..1000 {
+            i.hash(&mut hasher);
+            let rng = hasher.finish();
+            let op = rng % 3 == 0;
+            let key = (rng / 2) % 50;
+            let val = (rng / 100) % 1000;
+            if op {
+                map.insert(key, val);
+            } else {
+                map.get(&key);
+            }
+        }
+    }
+}
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 035c0e64233..3c13118122c 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -22,6 +22,10 @@ pub enum TerminationInfo {
         help: Option<String>,
         history: Option<TagHistory>,
     },
+    TreeBorrowsUb {
+        msg: String,
+        // FIXME: incomplete
+    },
     Int2PtrWithStrictProvenance,
     Deadlock,
     MultipleSymbolDefinitions {
@@ -61,6 +65,7 @@ impl fmt::Display for TerminationInfo {
                     "integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`"
                 ),
             StackedBorrowsUb { msg, .. } => write!(f, "{msg}"),
+            TreeBorrowsUb { msg } => write!(f, "{msg}"),
             Deadlock => write!(f, "the evaluated program deadlocked"),
             MultipleSymbolDefinitions { link_name, .. } =>
                 write!(f, "multiple definitions of symbol `{link_name}`"),
@@ -184,7 +189,8 @@ pub fn report_error<'tcx, 'mir>(
             Abort(_) => Some("abnormal termination"),
             UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance =>
                 Some("unsupported operation"),
-            StackedBorrowsUb { .. } | DataRace { .. } => Some("Undefined Behavior"),
+            StackedBorrowsUb { .. } | TreeBorrowsUb { .. } | DataRace { .. } =>
+                Some("Undefined Behavior"),
             Deadlock => Some("deadlock"),
             MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None,
         };
@@ -212,6 +218,12 @@ pub fn report_error<'tcx, 'mir>(
                     }
                 }
                 helps
+            },
+            TreeBorrowsUb { .. } => {
+                let helps = vec![
+                    (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental")),
+                ];
+                helps
             }
             MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } =>
                 vec![
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 8443e907938..a32b18595b5 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -87,7 +87,7 @@ pub struct MiriConfig {
     pub env: Vec<(OsString, OsString)>,
     /// Determine if validity checking is enabled.
     pub validate: bool,
-    /// Determines if Stacked Borrows is enabled.
+    /// Determines if Stacked Borrows or Tree Borrows is enabled.
     pub borrow_tracker: Option<BorrowTrackerMethod>,
     /// Controls alignment checking.
     pub check_alignment: AlignmentCheck,
@@ -134,7 +134,7 @@ pub struct MiriConfig {
     pub preemption_rate: f64,
     /// Report the current instruction being executed every N basic blocks.
     pub report_progress: Option<u32>,
-    /// Whether Stacked Borrows retagging should recurse into fields of datatypes.
+    /// Whether Stacked Borrows and Tree Borrows retagging should recurse into fields of datatypes.
     pub retag_fields: RetagFields,
     /// The location of a shared object file to load when calling external functions
     /// FIXME! consider allowing users to specify paths to multiple SO files, or to a directory
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index ed3dd741a8b..21a413002d0 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -1,5 +1,6 @@
 pub mod convert;
 
+use std::any::Any;
 use std::cmp;
 use std::iter;
 use std::num::NonZeroUsize;
@@ -23,7 +24,23 @@ use rand::RngCore;
 
 use crate::*;
 
-impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+/// A trait to work around not having trait object upcasting:
+/// Add `AsAny` as supertrait and your trait objects can be turned into `&dyn Any` on which you can
+/// then call `downcast`.
+pub trait AsAny: Any {
+    fn as_any(&self) -> &dyn Any;
+    fn as_any_mut(&mut self) -> &mut dyn Any;
+}
+impl<T: Any> AsAny for T {
+    #[inline(always)]
+    fn as_any(&self) -> &dyn Any {
+        self
+    }
+    #[inline(always)]
+    fn as_any_mut(&mut self) -> &mut dyn Any {
+        self
+    }
+}
 
 // This mapping should match `decode_error_kind` in
 // <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/unix/mod.rs>.
@@ -119,6 +136,7 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>)
     }
 }
 
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     /// Checks if the given crate/module exists.
     fn have_module(&self, path: &[&str]) -> bool {
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index f64f216520f..01d0f01d319 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -9,6 +9,7 @@
 #![feature(nonzero_ops)]
 #![feature(local_key_cell_methods)]
 #![feature(is_terminal)]
+#![feature(round_ties_even)]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,
@@ -94,6 +95,7 @@ pub use crate::shims::EvalContextExt as _;
 pub use crate::borrow_tracker::stacked_borrows::{
     EvalContextExt as _, Item, Permission, Stack, Stacks,
 };
+pub use crate::borrow_tracker::tree_borrows::{EvalContextExt as _, Tree};
 pub use crate::borrow_tracker::{
     BorTag, BorrowTrackerMethod, CallId, EvalContextExt as _, RetagFields,
 };
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 969c81f7e32..c4baeb2a73b 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -38,7 +38,7 @@ pub const SIGRTMAX: i32 = 42;
 
 /// Extra data stored with each stack frame
 pub struct FrameExtra<'tcx> {
-    /// Extra data for Stacked Borrows.
+    /// Extra data for the Borrow Tracker.
     pub borrow_tracker: Option<borrow_tracker::FrameState>,
 
     /// If this is Some(), then this is a special "catch unwind" frame (the frame of `try_fn`
@@ -146,7 +146,7 @@ impl fmt::Display for MiriMemoryKind {
 pub enum Provenance {
     Concrete {
         alloc_id: AllocId,
-        /// Stacked Borrows tag.
+        /// Borrow Tracker tag.
         tag: BorTag,
     },
     Wildcard,
@@ -195,7 +195,7 @@ impl fmt::Debug for Provenance {
                 } else {
                     write!(f, "[{alloc_id:?}]")?;
                 }
-                // Print Stacked Borrows tag.
+                // Print Borrow Tracker tag.
                 write!(f, "{tag:?}")?;
             }
             Provenance::Wildcard => {
@@ -822,7 +822,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
     }
 
     #[inline(always)]
-    fn ignore_checkable_overflow_assertions(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
+    fn ignore_optional_overflow_checks(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
         !ecx.tcx.sess.overflow_checks()
     }
 
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 03275ed4ed1..73439133af2 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -232,6 +232,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         }
     }
 
+    /// Read bytes from a `(ptr, len)` argument
+    fn read_byte_slice<'i>(&'i self, bytes: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, &'i [u8]>
+    where
+        'mir: 'i,
+    {
+        let this = self.eval_context_ref();
+        let (ptr, len) = this.read_immediate(bytes)?.to_scalar_pair();
+        let ptr = ptr.to_pointer(this)?;
+        let len = len.to_target_usize(this)?;
+        let bytes = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
+        Ok(bytes)
+    }
+
     /// Emulates calling a foreign item, failing if the item is not supported.
     /// This function will handle `goto_block` if needed.
     /// Returns Ok(None) if the foreign item was completely handled
@@ -427,13 +440,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 })?;
                 this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
             }
-            "miri_print_borrow_stacks" => {
-                let [id] = this.check_shim(abi, Abi::Rust, link_name, args)?;
+            "miri_print_borrow_state" => {
+                let [id, show_unnamed] = this.check_shim(abi, Abi::Rust, link_name, args)?;
                 let id = this.read_scalar(id)?.to_u64()?;
+                let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?;
                 if let Some(id) = std::num::NonZeroU64::new(id) {
-                    this.print_stacks(AllocId(id))?;
+                    this.print_borrow_state(AllocId(id), show_unnamed)?;
                 }
             }
+            "miri_pointer_name" => {
+                // This associates a name to a tag. Very useful for debugging, and also makes
+                // tests more strict.
+                let [ptr, nth_parent, name] = this.check_shim(abi, Abi::Rust, link_name, args)?;
+                let ptr = this.read_pointer(ptr)?;
+                let nth_parent = this.read_scalar(nth_parent)?.to_u8()?;
+                let name = this.read_byte_slice(name)?;
+                // We must make `name` owned because we need to
+                // end the shared borrow from `read_byte_slice` before we can
+                // start the mutable borrow for `give_pointer_debug_name`.
+                let name = String::from_utf8_lossy(name).into_owned();
+                this.give_pointer_debug_name(ptr, nth_parent, &name)?;
+            }
             "miri_static_root" => {
                 let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
@@ -487,12 +514,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             // Writes some bytes to the interpreter's stdout/stderr. See the
             // README for details.
             "miri_write_to_stdout" | "miri_write_to_stderr" => {
-                let [bytes] = this.check_shim(abi, Abi::Rust, link_name, args)?;
-                let (ptr, len) = this.read_immediate(bytes)?.to_scalar_pair();
-                let ptr = ptr.to_pointer(this)?;
-                let len = len.to_target_usize(this)?;
-                let msg = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
-
+                let [msg] = this.check_shim(abi, Abi::Rust, link_name, args)?;
+                let msg = this.read_byte_slice(msg)?;
                 // Note: we're ignoring errors writing to host stdout/stderr.
                 let _ignore = match link_name.as_str() {
                     "miri_write_to_stdout" => std::io::stdout().write_all(msg),
diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs
index d21a1560699..9ecbb18ef5a 100644
--- a/src/tools/miri/src/shims/intrinsics/mod.rs
+++ b/src/tools/miri/src/shims/intrinsics/mod.rs
@@ -157,6 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             | "ceilf32"
             | "truncf32"
             | "roundf32"
+            | "rintf32"
             => {
                 let [f] = check_arg_count(args)?;
                 // FIXME: Using host floats.
@@ -174,6 +175,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     "ceilf32" => f.ceil(),
                     "truncf32" => f.trunc(),
                     "roundf32" => f.round(),
+                    "rintf32" => f.round_ties_even(),
                     _ => bug!(),
                 };
                 this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?;
@@ -192,6 +194,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             | "ceilf64"
             | "truncf64"
             | "roundf64"
+            | "rintf64"
             => {
                 let [f] = check_arg_count(args)?;
                 // FIXME: Using host floats.
@@ -209,6 +212,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     "ceilf64" => f.ceil(),
                     "truncf64" => f.trunc(),
                     "roundf64" => f.round(),
+                    "rintf64" => f.round_ties_even(),
                     _ => bug!(),
                 };
                 this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?;
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index d05c4d98fad..1eca389e984 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -17,7 +17,6 @@ use crate::shims::os_str::bytes_to_os_str;
 use crate::*;
 use shims::os_str::os_str_to_bytes;
 use shims::time::system_time_to_duration;
-use shims::unix::linux::fd::epoll::Epoll;
 
 #[derive(Debug)]
 pub struct FileHandle {
@@ -25,17 +24,9 @@ pub struct FileHandle {
     writable: bool,
 }
 
-pub trait FileDescriptor: std::fmt::Debug {
+pub trait FileDescriptor: std::fmt::Debug + helpers::AsAny {
     fn name(&self) -> &'static str;
 
-    fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> {
-        throw_unsup_format!("{} cannot be used as FileHandle", self.name());
-    }
-
-    fn as_epoll_handle<'tcx>(&mut self) -> InterpResult<'tcx, &mut Epoll> {
-        throw_unsup_format!("not an epoll file descriptor");
-    }
-
     fn read<'tcx>(
         &mut self,
         _communicate_allowed: bool,
@@ -69,7 +60,9 @@ pub trait FileDescriptor: std::fmt::Debug {
 
     fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>>;
 
-    fn is_tty(&self) -> bool;
+    fn is_tty(&self) -> bool {
+        false
+    }
 
     #[cfg(unix)]
     fn as_unix_host_fd(&self) -> Option<i32> {
@@ -82,10 +75,6 @@ impl FileDescriptor for FileHandle {
         "FILE"
     }
 
-    fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> {
-        Ok(self)
-    }
-
     fn read<'tcx>(
         &mut self,
         communicate_allowed: bool,
@@ -271,10 +260,6 @@ impl FileDescriptor for NullOutput {
     fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
         Ok(Box::new(NullOutput))
     }
-
-    fn is_tty(&self) -> bool {
-        false
-    }
 }
 
 #[derive(Debug)]
@@ -694,7 +679,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") {
             if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
                 // FIXME: Support fullfsync for all FDs
-                let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
+                let FileHandle { file, writable } =
+                    file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| {
+                        err_unsup_format!(
+                            "`F_FULLFSYNC` is only supported on file-backed file descriptors"
+                        )
+                    })?;
                 let io_result = maybe_sync_file(file, *writable, File::sync_all);
                 this.try_unwrap_io_result(io_result)
             } else {
@@ -1530,7 +1520,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         Ok(Scalar::from_i32(
             if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) {
                 // FIXME: Support ftruncate64 for all FDs
-                let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
+                let FileHandle { file, writable } =
+                    file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| {
+                        err_unsup_format!(
+                            "`ftruncate64` is only supported on file-backed file descriptors"
+                        )
+                    })?;
                 if *writable {
                     if let Ok(length) = length.try_into() {
                         let result = file.set_len(length);
@@ -1571,7 +1566,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
             // FIXME: Support fsync for all FDs
-            let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
+            let FileHandle { file, writable } =
+                file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| {
+                    err_unsup_format!("`fsync` is only supported on file-backed file descriptors")
+                })?;
             let io_result = maybe_sync_file(file, *writable, File::sync_all);
             this.try_unwrap_io_result(io_result)
         } else {
@@ -1593,7 +1591,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
             // FIXME: Support fdatasync for all FDs
-            let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
+            let FileHandle { file, writable } =
+                file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| {
+                    err_unsup_format!(
+                        "`fdatasync` is only supported on file-backed file descriptors"
+                    )
+                })?;
             let io_result = maybe_sync_file(file, *writable, File::sync_data);
             this.try_unwrap_io_result(io_result)
         } else {
@@ -1638,7 +1641,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
             // FIXME: Support sync_data_range for all FDs
-            let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
+            let FileHandle { file, writable } =
+                file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| {
+                    err_unsup_format!(
+                        "`sync_data_range` is only supported on file-backed file descriptors"
+                    )
+                })?;
             let io_result = maybe_sync_file(file, *writable, File::sync_data);
             Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
         } else {
@@ -1942,7 +1950,16 @@ impl FileMetadata {
     ) -> InterpResult<'tcx, Option<FileMetadata>> {
         let option = ecx.machine.file_handler.handles.get(&fd);
         let file = match option {
-            Some(file_descriptor) => &file_descriptor.as_file_handle()?.file,
+            Some(file_descriptor) =>
+                &file_descriptor
+                    .as_any()
+                    .downcast_ref::<FileHandle>()
+                    .ok_or_else(|| {
+                        err_unsup_format!(
+                            "obtaining metadata is only supported on file-backed file descriptors"
+                        )
+                    })?
+                    .file,
             None => return ecx.handle_not_found().map(|_: i32| None),
         };
         let metadata = file.metadata();
diff --git a/src/tools/miri/src/shims/unix/linux/fd.rs b/src/tools/miri/src/shims/unix/linux/fd.rs
index fd4927fa10c..3c4a678e598 100644
--- a/src/tools/miri/src/shims/unix/linux/fd.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd.rs
@@ -80,7 +80,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             let event = EpollEvent { events, data };
 
             if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
-                let epfd = epfd.as_epoll_handle()?;
+                let epfd = epfd
+                    .as_any_mut()
+                    .downcast_mut::<Epoll>()
+                    .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?;
 
                 epfd.file_descriptors.insert(fd, event);
                 Ok(Scalar::from_i32(0))
@@ -89,7 +92,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             }
         } else if op == epoll_ctl_del {
             if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
-                let epfd = epfd.as_epoll_handle()?;
+                let epfd = epfd
+                    .as_any_mut()
+                    .downcast_mut::<Epoll>()
+                    .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?;
 
                 epfd.file_descriptors.remove(&fd);
                 Ok(Scalar::from_i32(0))
@@ -148,7 +154,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         let numevents = 0;
         if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
-            let _epfd = epfd.as_epoll_handle()?;
+            let _epfd = epfd
+                .as_any_mut()
+                .downcast_mut::<Epoll>()
+                .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
 
             // FIXME return number of events ready when scheme for marking events ready exists
             Ok(Scalar::from_i32(numevents))
diff --git a/src/tools/miri/src/shims/unix/linux/fd/epoll.rs b/src/tools/miri/src/shims/unix/linux/fd/epoll.rs
index e33673fecf6..a429caaf8f4 100644
--- a/src/tools/miri/src/shims/unix/linux/fd/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd/epoll.rs
@@ -32,18 +32,10 @@ impl FileDescriptor for Epoll {
         "epoll"
     }
 
-    fn as_epoll_handle<'tcx>(&mut self) -> InterpResult<'tcx, &mut Epoll> {
-        Ok(self)
-    }
-
     fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
         Ok(Box::new(self.clone()))
     }
 
-    fn is_tty(&self) -> bool {
-        false
-    }
-
     fn close<'tcx>(
         self: Box<Self>,
         _communicate_allowed: bool,
diff --git a/src/tools/miri/src/shims/unix/linux/fd/event.rs b/src/tools/miri/src/shims/unix/linux/fd/event.rs
index b28a6e0c56e..1db020bb7b6 100644
--- a/src/tools/miri/src/shims/unix/linux/fd/event.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd/event.rs
@@ -28,10 +28,6 @@ impl FileDescriptor for Event {
         Ok(Box::new(Event { val: self.val.clone() }))
     }
 
-    fn is_tty(&self) -> bool {
-        false
-    }
-
     fn close<'tcx>(
         self: Box<Self>,
         _communicate_allowed: bool,
diff --git a/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs b/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs
index f9e56b4a2b4..6adae88235f 100644
--- a/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs
@@ -19,10 +19,6 @@ impl FileDescriptor for SocketPair {
         Ok(Box::new(SocketPair))
     }
 
-    fn is_tty(&self) -> bool {
-        false
-    }
-
     fn close<'tcx>(
         self: Box<Self>,
         _communicate_allowed: bool,
diff --git a/src/tools/miri/src/shims/windows/dlsym.rs b/src/tools/miri/src/shims/windows/dlsym.rs
index 60dd299c438..7e2051fc98a 100644
--- a/src/tools/miri/src/shims/windows/dlsym.rs
+++ b/src/tools/miri/src/shims/windows/dlsym.rs
@@ -1,5 +1,4 @@
 use rustc_middle::mir;
-use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 
 use log::trace;
@@ -11,7 +10,6 @@ use crate::*;
 
 #[derive(Debug, Copy, Clone)]
 pub enum Dlsym {
-    NtWriteFile,
     SetThreadDescription,
     WaitOnAddress,
     WakeByAddressSingle,
@@ -23,7 +21,6 @@ impl Dlsym {
     pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
         Ok(match name {
             "GetSystemTimePreciseAsFileTime" => None,
-            "NtWriteFile" => Some(Dlsym::NtWriteFile),
             "SetThreadDescription" => Some(Dlsym::SetThreadDescription),
             "WaitOnAddress" => Some(Dlsym::WaitOnAddress),
             "WakeByAddressSingle" => Some(Dlsym::WakeByAddressSingle),
@@ -49,72 +46,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         this.check_abi(abi, Abi::System { unwind: false })?;
 
         match dlsym {
-            Dlsym::NtWriteFile => {
-                if !this.frame_in_std() {
-                    throw_unsup_format!(
-                        "`NtWriteFile` support is crude and just enough for stdout to work"
-                    );
-                }
-
-                let [
-                    handle,
-                    _event,
-                    _apc_routine,
-                    _apc_context,
-                    io_status_block,
-                    buf,
-                    n,
-                    byte_offset,
-                    _key,
-                ] = check_arg_count(args)?;
-                let handle = this.read_target_isize(handle)?;
-                let buf = this.read_pointer(buf)?;
-                let n = this.read_scalar(n)?.to_u32()?;
-                let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer
-                let io_status_block = this.deref_operand(io_status_block)?;
-
-                if byte_offset != 0 {
-                    throw_unsup_format!(
-                        "`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported"
-                    );
-                }
-
-                let written = if handle == -11 || handle == -12 {
-                    // stdout/stderr
-                    use std::io::{self, Write};
-
-                    let buf_cont =
-                        this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?;
-                    let res = if this.machine.mute_stdout_stderr {
-                        Ok(buf_cont.len())
-                    } else if handle == -11 {
-                        io::stdout().write(buf_cont)
-                    } else {
-                        io::stderr().write(buf_cont)
-                    };
-                    // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that.
-                    res.ok().map(|n| u32::try_from(n).unwrap())
-                } else {
-                    throw_unsup_format!(
-                        "on Windows, writing to anything except stdout/stderr is not supported"
-                    )
-                };
-                // We have to put the result into io_status_block.
-                if let Some(n) = written {
-                    let io_status_information =
-                        this.mplace_field_named(&io_status_block, "Information")?;
-                    this.write_scalar(
-                        Scalar::from_target_usize(n.into(), this),
-                        &io_status_information.into(),
-                    )?;
-                }
-                // Return whether this was a success. >= 0 is success.
-                // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
-                this.write_scalar(
-                    Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }),
-                    dest,
-                )?;
-            }
             Dlsym::SetThreadDescription => {
                 let [handle, name] = check_arg_count(args)?;
 
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index a3d7176a976..665c7ed438f 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -69,6 +69,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 this.write_scalar(result, dest)?;
             }
 
+            // File related shims
+            "NtWriteFile" => {
+                if !this.frame_in_std() {
+                    throw_unsup_format!(
+                        "`NtWriteFile` support is crude and just enough for stdout to work"
+                    );
+                }
+
+                let [
+                    handle,
+                    _event,
+                    _apc_routine,
+                    _apc_context,
+                    io_status_block,
+                    buf,
+                    n,
+                    byte_offset,
+                    _key,
+                ] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
+                let handle = this.read_target_isize(handle)?;
+                let buf = this.read_pointer(buf)?;
+                let n = this.read_scalar(n)?.to_u32()?;
+                let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer
+                let io_status_block = this.deref_operand(io_status_block)?;
+
+                if byte_offset != 0 {
+                    throw_unsup_format!(
+                        "`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported"
+                    );
+                }
+
+                let written = if handle == -11 || handle == -12 {
+                    // stdout/stderr
+                    use std::io::{self, Write};
+
+                    let buf_cont =
+                        this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?;
+                    let res = if this.machine.mute_stdout_stderr {
+                        Ok(buf_cont.len())
+                    } else if handle == -11 {
+                        io::stdout().write(buf_cont)
+                    } else {
+                        io::stderr().write(buf_cont)
+                    };
+                    // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that.
+                    res.ok().map(|n| u32::try_from(n).unwrap())
+                } else {
+                    throw_unsup_format!(
+                        "on Windows, writing to anything except stdout/stderr is not supported"
+                    )
+                };
+                // We have to put the result into io_status_block.
+                if let Some(n) = written {
+                    let io_status_information =
+                        this.mplace_field_named(&io_status_block, "Information")?;
+                    this.write_scalar(
+                        Scalar::from_target_usize(n.into(), this),
+                        &io_status_information.into(),
+                    )?;
+                }
+                // Return whether this was a success. >= 0 is success.
+                // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
+                this.write_scalar(
+                    Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }),
+                    dest,
+                )?;
+            }
+
             // Allocation
             "HeapAlloc" => {
                 let [handle, flags, size] =
diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs
index 1d7ed34c59a..21eaeabe6ad 100644
--- a/src/tools/miri/tests/compiletest.rs
+++ b/src/tools/miri/tests/compiletest.rs
@@ -139,8 +139,9 @@ regexes! {
     STDOUT:
     // Windows file paths
     r"\\"                           => "/",
-    // erase Stacked Borrows tags
+    // erase borrow tags
     "<[0-9]+>"                      => "<TAG>",
+    "<[0-9]+="                      => "<TAG=",
 }
 
 regexes! {
@@ -149,8 +150,9 @@ regexes! {
     r"\.rs:[0-9]+:[0-9]+(: [0-9]+:[0-9]+)?" => ".rs:LL:CC",
     // erase alloc ids
     "alloc[0-9]+"                    => "ALLOC",
-    // erase Stacked Borrows tags
+    // erase borrow tags
     "<[0-9]+>"                       => "<TAG>",
+    "<[0-9]+="                       => "<TAG=",
     // erase whitespace that differs between platforms
     r" +at (.*\.rs)"                 => " at $1",
     // erase generics in backtraces
diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs
index a63cd03366f..0637e08af9b 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs
+++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs
@@ -1,4 +1,4 @@
-//! Make sure that a retag acts like a write for the data race model.
+//! Make sure that a retag acts like a read for the data race model.
 //@compile-flags: -Zmiri-preemption-rate=0
 #[derive(Copy, Clone)]
 struct SendPtr(*mut u8);
diff --git a/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.rs b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.rs
new file mode 100644
index 00000000000..122a8ff8752
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.rs
@@ -0,0 +1,19 @@
+//@compile-flags: -Zmiri-tree-borrows
+
+// Check that TB properly rejects alternating Reads and Writes, but tolerates
+// alternating only Reads to Reserved mutable references.
+pub fn main() {
+    let x = &mut 0u8;
+    let y = unsafe { &mut *(x as *mut u8) };
+    // Foreign Read, but this is a no-op from the point of view of y (still Reserved)
+    let _val = *x;
+    // Now we activate y, for this to succeed y needs to not have been Frozen
+    // by the previous operation
+    *y += 1; // Success
+    // This time y gets Frozen...
+    let _val = *x;
+    // ... and the next Write attempt fails.
+    *y += 1; // Failure //~ ERROR: /write access through .* is forbidden/
+    let _val = *x;
+    *y += 1; // Unreachable
+}
diff --git a/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr
new file mode 100644
index 00000000000..7c5bcd4e7b0
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr
@@ -0,0 +1,14 @@
+error: Undefined Behavior: write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen.
+  --> $DIR/alternate-read-write.rs:LL:CC
+   |
+LL |     *y += 1; // Failure
+   |     ^^^^^^^ write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen.
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/alternate-read-write.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.rs b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.rs
new file mode 100644
index 00000000000..215100de0a1
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.rs
@@ -0,0 +1,42 @@
+//! Race-condition-like interaction between a read and a reborrow.
+//! Even though no write or fake write occurs, reads have an effect on protected
+//! Reserved. This is a protected-retag/read data race, but is not *detected* as
+//! a data race violation because reborrows are not writes.
+//!
+//! This test is sensitive to the exact schedule so we disable preemption.
+//@compile-flags: -Zmiri-tree-borrows -Zmiri-preemption-rate=0
+use std::ptr::addr_of_mut;
+use std::thread;
+
+#[derive(Copy, Clone)]
+struct SendPtr(*mut u8);
+
+unsafe impl Send for SendPtr {}
+
+// First thread is just a reborrow, but for an instant `x` is
+// protected and thus vulnerable to foreign reads.
+fn thread_1(x: &mut u8) -> SendPtr {
+    thread::yield_now(); // make the other thread go first
+    SendPtr(x as *mut u8)
+}
+
+// Second thread simply performs a read.
+fn thread_2(x: &u8) {
+    let _val = *x;
+}
+
+fn main() {
+    let mut x = 0u8;
+    let x_1 = unsafe { &mut *addr_of_mut!(x) };
+    let xg = unsafe { &*addr_of_mut!(x) };
+
+    // The two threads are executed in parallel on aliasing pointers.
+    // UB occurs if the read of thread_2 occurs while the protector of thread_1
+    // is in place.
+    let hf = thread::spawn(move || thread_1(x_1));
+    let hg = thread::spawn(move || thread_2(xg));
+    let SendPtr(p) = hf.join().unwrap();
+    let () = hg.join().unwrap();
+
+    unsafe { *p = 1 }; //~ ERROR: /write access through .* is forbidden/
+}
diff --git a/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr
new file mode 100644
index 00000000000..a078d18d3b0
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr
@@ -0,0 +1,14 @@
+error: Undefined Behavior: write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen.
+  --> $DIR/fragile-data-race.rs:LL:CC
+   |
+LL |     unsafe { *p = 1 };
+   |              ^^^^^^ write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen.
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/fragile-data-race.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/tree-borrows/outside-range.rs b/src/tools/miri/tests/fail/tree-borrows/outside-range.rs
new file mode 100644
index 00000000000..8450e1c168d
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/outside-range.rs
@@ -0,0 +1,22 @@
+//@compile-flags: -Zmiri-tree-borrows
+
+// Check that in the case of locations outside the range of a pointer,
+// protectors trigger if and only if the location has already been accessed
+fn main() {
+    unsafe {
+        let data = &mut [0u8, 1, 2, 3];
+        let raw = data.as_mut_ptr();
+        stuff(&mut *raw, raw);
+    }
+}
+
+unsafe fn stuff(x: &mut u8, y: *mut u8) {
+    let xraw = x as *mut u8;
+    // No issue here: location 1 is not accessed
+    *y.add(1) = 42;
+    // Still no issue: location 2 is not invalidated
+    let _val = *xraw.add(2);
+    // However protector triggers if location is both accessed and invalidated
+    let _val = *xraw.add(3);
+    *y.add(3) = 42; //~ ERROR: /write access through .* is forbidden/
+}
diff --git a/src/tools/miri/tests/fail/tree-borrows/outside-range.stderr b/src/tools/miri/tests/fail/tree-borrows/outside-range.stderr
new file mode 100644
index 00000000000..4396c63679e
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/outside-range.stderr
@@ -0,0 +1,19 @@
+error: Undefined Behavior: write access through <TAG> is forbidden because it is a foreign tag for <TAG>, which would hence change from Reserved to Disabled, but <TAG> is protected
+  --> $DIR/outside-range.rs:LL:CC
+   |
+LL |     *y.add(3) = 42;
+   |     ^^^^^^^^^^^^^^ write access through <TAG> is forbidden because it is a foreign tag for <TAG>, which would hence change from Reserved to Disabled, but <TAG> is protected
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = note: BACKTRACE:
+   = note: inside `stuff` at $DIR/outside-range.rs:LL:CC
+note: inside `main`
+  --> $DIR/outside-range.rs:LL:CC
+   |
+LL |         stuff(&mut *raw, raw);
+   |         ^^^^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/tree-borrows/read-to-local.rs b/src/tools/miri/tests/fail/tree-borrows/read-to-local.rs
new file mode 100644
index 00000000000..025b7ad22dc
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/read-to-local.rs
@@ -0,0 +1,14 @@
+//@compile-flags: -Zmiri-tree-borrows
+
+// Read to local variable kills reborrows *and* raw pointers derived from them.
+// This test would succeed under Stacked Borrows.
+fn main() {
+    unsafe {
+        let mut root = 6u8;
+        let mref = &mut root;
+        let ptr = mref as *mut u8;
+        *ptr = 0; // Write
+        assert_eq!(root, 0); // Parent Read
+        *ptr = 0; //~ ERROR: /write access through .* is forbidden/
+    }
+}
diff --git a/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr b/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr
new file mode 100644
index 00000000000..7d9367c87d0
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr
@@ -0,0 +1,14 @@
+error: Undefined Behavior: write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen.
+  --> $DIR/read-to-local.rs:LL:CC
+   |
+LL |         *ptr = 0;
+   |         ^^^^^^^^ write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen.
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/read-to-local.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.rs b/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.rs
new file mode 100644
index 00000000000..872efe3ad59
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.rs
@@ -0,0 +1,34 @@
+//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0
+
+// Check how a Reserved with interior mutability
+// responds to a Foreign Write under a Protector
+#[path = "../../../utils/mod.rs"]
+mod utils;
+use utils::macros::*;
+
+use std::cell::UnsafeCell;
+
+fn main() {
+    unsafe {
+        let n = &mut UnsafeCell::new(0u8);
+        name!(n.get(), "base");
+        let x = &mut *(n as *mut UnsafeCell<_>);
+        name!(x.get(), "x");
+        let y = (&mut *n).get();
+        name!(y);
+        write_second(x, y);
+        unsafe fn write_second(x: &mut UnsafeCell<u8>, y: *mut u8) {
+            let alloc_id = alloc_id!(x.get());
+            name!(x.get(), "callee:x");
+            name!(x.get()=>1, "caller:x");
+            name!(y, "callee:y");
+            name!(y, "caller:y");
+            print_state!(alloc_id);
+            // Right before the faulty Write, x is
+            // - Reserved
+            // - with interior mut
+            // - Protected
+            *y = 1; //~ ERROR: /write access through .* is forbidden/
+        }
+    }
+}
diff --git a/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.stderr
new file mode 100644
index 00000000000..8ae1c09470a
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.stderr
@@ -0,0 +1,28 @@
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Re*|    └─┬──<TAG=base>
+| Re*|      ├─┬──<TAG=x>
+| Re*|      │ └─┬──<TAG=caller:x>
+| Re*|      │   └────<TAG=callee:x> Strongly protected
+| Re*|      └────<TAG=y,callee:y,caller:y>
+──────────────────────────────────────────────────────────────────────
+error: Undefined Behavior: write access through <TAG> (also named 'y,callee:y,caller:y') is forbidden because it is a foreign tag for <TAG> (also named 'callee:x'), which would hence change from Reserved to Disabled, but <TAG> (also named 'callee:x') is protected
+  --> $DIR/cell-protected-write.rs:LL:CC
+   |
+LL |             *y = 1;
+   |             ^^^^^^ write access through <TAG> (also named 'y,callee:y,caller:y') is forbidden because it is a foreign tag for <TAG> (also named 'callee:x'), which would hence change from Reserved to Disabled, but <TAG> (also named 'callee:x') is protected
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = note: BACKTRACE:
+   = note: inside `main::write_second` at $DIR/cell-protected-write.rs:LL:CC
+note: inside `main`
+  --> $DIR/cell-protected-write.rs:LL:CC
+   |
+LL |         write_second(x, y);
+   |         ^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.rs b/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.rs
new file mode 100644
index 00000000000..3a1205a84f7
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.rs
@@ -0,0 +1,32 @@
+//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0
+
+#[path = "../../../utils/mod.rs"]
+mod utils;
+use utils::macros::*;
+
+// Check how a Reserved without interior mutability responds to a Foreign
+// Write when under a protector
+fn main() {
+    unsafe {
+        let n = &mut 0u8;
+        name!(n);
+        let x = &mut *(n as *mut _);
+        name!(x);
+        let y = (&mut *n) as *mut _;
+        name!(y);
+        write_second(x, y);
+        unsafe fn write_second(x: &mut u8, y: *mut u8) {
+            let alloc_id = alloc_id!(x);
+            name!(x, "callee:x");
+            name!(x=>1, "caller:x");
+            name!(y, "callee:y");
+            name!(y, "caller:y");
+            print_state!(alloc_id);
+            // Right before the faulty Write, x is
+            // - Reserved
+            // - Protected
+            // The Write turns it Disabled
+            *y = 0; //~ ERROR: /write access through .* is forbidden/
+        }
+    }
+}
diff --git a/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.stderr b/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.stderr
new file mode 100644
index 00000000000..a199fc0f0da
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.stderr
@@ -0,0 +1,28 @@
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Res|    └─┬──<TAG=n>
+| Res|      ├─┬──<TAG=x>
+| Res|      │ └─┬──<TAG=caller:x>
+| Res|      │   └────<TAG=callee:x> Strongly protected
+| Res|      └────<TAG=y,callee:y,caller:y>
+──────────────────────────────────────────────────────────────────────
+error: Undefined Behavior: write access through <TAG> (also named 'y,callee:y,caller:y') is forbidden because it is a foreign tag for <TAG> (also named 'callee:x'), which would hence change from Reserved to Disabled, but <TAG> (also named 'callee:x') is protected
+  --> $DIR/int-protected-write.rs:LL:CC
+   |
+LL |             *y = 0;
+   |             ^^^^^^ write access through <TAG> (also named 'y,callee:y,caller:y') is forbidden because it is a foreign tag for <TAG> (also named 'callee:x'), which would hence change from Reserved to Disabled, but <TAG> (also named 'callee:x') is protected
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = note: BACKTRACE:
+   = note: inside `main::write_second` at $DIR/int-protected-write.rs:LL:CC
+note: inside `main`
+  --> $DIR/int-protected-write.rs:LL:CC
+   |
+LL |         write_second(x, y);
+   |         ^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/tree-borrows/retag-data-race.rs b/src/tools/miri/tests/fail/tree-borrows/retag-data-race.rs
new file mode 100644
index 00000000000..8ef3d23e804
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/retag-data-race.rs
@@ -0,0 +1,28 @@
+//! Make sure that a retag acts like a read for the data race model.
+//! This is a retag/write race condition.
+//!
+//! This test is sensitive to the exact schedule so we disable preemption.
+//@compile-flags: -Zmiri-tree-borrows -Zmiri-preemption-rate=0
+#[derive(Copy, Clone)]
+struct SendPtr(*mut u8);
+
+unsafe impl Send for SendPtr {}
+
+unsafe fn thread_1(SendPtr(p): SendPtr) {
+    let _r = &*p;
+}
+
+unsafe fn thread_2(SendPtr(p): SendPtr) {
+    *p = 5; //~ ERROR: Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>`
+}
+
+fn main() {
+    let mut x = 0;
+    let p = std::ptr::addr_of_mut!(x);
+    let p = SendPtr(p);
+
+    let t1 = std::thread::spawn(move || unsafe { thread_1(p) });
+    let t2 = std::thread::spawn(move || unsafe { thread_2(p) });
+    let _ = t1.join();
+    let _ = t2.join();
+}
diff --git a/src/tools/miri/tests/fail/tree-borrows/retag-data-race.stderr b/src/tools/miri/tests/fail/tree-borrows/retag-data-race.stderr
new file mode 100644
index 00000000000..f2cdfe7c314
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/retag-data-race.stderr
@@ -0,0 +1,25 @@
+error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here
+  --> $DIR/retag-data-race.rs:LL:CC
+   |
+LL |     *p = 5;
+   |     ^^^^^^ Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here
+   |
+help: and (1) occurred earlier here
+  --> $DIR/retag-data-race.rs:LL:CC
+   |
+LL |     let _r = &*p;
+   |              ^^^
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span):
+   = note: inside `thread_2` at $DIR/retag-data-race.rs:LL:CC
+note: inside closure
+  --> $DIR/retag-data-race.rs:LL:CC
+   |
+LL |     let t2 = std::thread::spawn(move || unsafe { thread_2(p) });
+   |                                                  ^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.rs b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.rs
new file mode 100644
index 00000000000..6695d36306b
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.rs
@@ -0,0 +1,27 @@
+//@compile-flags: -Zmiri-tree-borrows
+
+// We invalidate a reference during a 2-phase borrow by doing a Foreign
+// Write in between the initial reborrow and function entry. UB occurs
+// on function entry when reborrow from a Disabled fails.
+// This test would pass under Stacked Borrows, but Tree Borrows
+// is more strict on 2-phase borrows.
+
+struct Foo(u64);
+impl Foo {
+    #[rustfmt::skip] // rustfmt is wrong about which line contains an error
+    fn add(&mut self, n: u64) -> u64 { //~ ERROR: /read access through .* is forbidden/
+        self.0 + n
+    }
+}
+
+pub fn main() {
+    let mut f = Foo(0);
+    let inner = &mut f.0 as *mut u64;
+    let _res = f.add(unsafe {
+        let n = f.0;
+        // This is the access at fault, but it's not immediately apparent because
+        // the reference that got invalidated is not under a Protector.
+        *inner = 42;
+        n
+    });
+}
diff --git a/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr
new file mode 100644
index 00000000000..e511eb9cf8f
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr
@@ -0,0 +1,26 @@
+error: Undefined Behavior: read access through <TAG> is forbidden because it is a child of <TAG> which is Disabled.
+  --> $DIR/write-during-2phase.rs:LL:CC
+   |
+LL |     fn add(&mut self, n: u64) -> u64 {
+   |            ^^^^^^^^^ read access through <TAG> is forbidden because it is a child of <TAG> which is Disabled.
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = note: BACKTRACE:
+   = note: inside `Foo::add` at $DIR/write-during-2phase.rs:LL:CC
+note: inside `main`
+  --> $DIR/write-during-2phase.rs:LL:CC
+   |
+LL |       let _res = f.add(unsafe {
+   |  ________________^
+LL | |         let n = f.0;
+LL | |         // This is the access at fault, but it's not immediately apparent because
+LL | |         // the reference that got invalidated is not under a Protector.
+LL | |         *inner = 42;
+LL | |         n
+LL | |     });
+   | |______^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/pass/adjacent-allocs.rs b/src/tools/miri/tests/pass/adjacent-allocs.rs
index 0051c62121c..cbf41d68b57 100644
--- a/src/tools/miri/tests/pass/adjacent-allocs.rs
+++ b/src/tools/miri/tests/pass/adjacent-allocs.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-permissive-provenance
 
 fn ensure_allocs_can_be_adjacent() {
diff --git a/src/tools/miri/tests/pass/associated-const.rs b/src/tools/miri/tests/pass/associated-const.rs
index 2ff08ffc4bf..331fbfcefde 100644
--- a/src/tools/miri/tests/pass/associated-const.rs
+++ b/src/tools/miri/tests/pass/associated-const.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 trait Foo {
     const ID: i32;
 }
diff --git a/src/tools/miri/tests/pass/assume_bug.rs b/src/tools/miri/tests/pass/assume_bug.rs
index e14f875c022..662b9015088 100644
--- a/src/tools/miri/tests/pass/assume_bug.rs
+++ b/src/tools/miri/tests/pass/assume_bug.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 fn main() {
     vec![()].into_iter();
 }
diff --git a/src/tools/miri/tests/pass/atomic.rs b/src/tools/miri/tests/pass/atomic.rs
index e3d80a78916..60b8ff87b59 100644
--- a/src/tools/miri/tests/pass/atomic.rs
+++ b/src/tools/miri/tests/pass/atomic.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-strict-provenance
 #![feature(strict_provenance, strict_provenance_atomic_ptr)]
 use std::sync::atomic::{
diff --git a/src/tools/miri/tests/pass/available-parallelism.rs b/src/tools/miri/tests/pass/available-parallelism.rs
index eb4d09b1f54..77fb78424ba 100644
--- a/src/tools/miri/tests/pass/available-parallelism.rs
+++ b/src/tools/miri/tests/pass/available-parallelism.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 fn main() {
     assert_eq!(std::thread::available_parallelism().unwrap().get(), 1);
 }
diff --git a/src/tools/miri/tests/pass/box-custom-alloc.rs b/src/tools/miri/tests/pass/box-custom-alloc.rs
index ef432a86d46..155e3d74ab9 100644
--- a/src/tools/miri/tests/pass/box-custom-alloc.rs
+++ b/src/tools/miri/tests/pass/box-custom-alloc.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 #![allow(incomplete_features)] // for trait upcasting
 #![feature(allocator_api, trait_upcasting)]
 
diff --git a/src/tools/miri/tests/pass/box.rs b/src/tools/miri/tests/pass/box.rs
index 7bbe7be516b..3bb481aab88 100644
--- a/src/tools/miri/tests/pass/box.rs
+++ b/src/tools/miri/tests/pass/box.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance
 #![feature(ptr_internals)]
 
 fn main() {
diff --git a/src/tools/miri/tests/pass/box.stderr b/src/tools/miri/tests/pass/box.stack.stderr
index 4c2fb40e110..4c2fb40e110 100644
--- a/src/tools/miri/tests/pass/box.stderr
+++ b/src/tools/miri/tests/pass/box.stack.stderr
diff --git a/src/tools/miri/tests/pass/box.stdout b/src/tools/miri/tests/pass/box.stack.stdout
index 230ef368da6..230ef368da6 100644
--- a/src/tools/miri/tests/pass/box.stdout
+++ b/src/tools/miri/tests/pass/box.stack.stdout
diff --git a/src/tools/miri/tests/pass/box.tree.stdout b/src/tools/miri/tests/pass/box.tree.stdout
new file mode 100644
index 00000000000..230ef368da6
--- /dev/null
+++ b/src/tools/miri/tests/pass/box.tree.stdout
@@ -0,0 +1,3 @@
+pair_foo = PairFoo { fst: Foo(42), snd: Foo(1337) }
+foo #0 = Foo(42)
+foo #1 = Foo(1337)
diff --git a/src/tools/miri/tests/pass/btreemap.rs b/src/tools/miri/tests/pass/btreemap.rs
index 040c648d474..b7c0406becc 100644
--- a/src/tools/miri/tests/pass/btreemap.rs
+++ b/src/tools/miri/tests/pass/btreemap.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-strict-provenance
 #![feature(btree_drain_filter)]
 use std::collections::{BTreeMap, BTreeSet};
diff --git a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs
index d76c23633da..ccf96b99672 100644
--- a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs
+++ b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 // Check that you can cast between different pointers to trait objects
 // whose vtable have the same kind (both lengths, or both trait pointers).
 
diff --git a/src/tools/miri/tests/pass/concurrency/channels.rs b/src/tools/miri/tests/pass/concurrency/channels.rs
index 53b57942d76..43086756b03 100644
--- a/src/tools/miri/tests/pass/concurrency/channels.rs
+++ b/src/tools/miri/tests/pass/concurrency/channels.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-strict-provenance
 
 use std::sync::mpsc::{channel, sync_channel};
diff --git a/src/tools/miri/tests/pass/concurrency/sync.rs b/src/tools/miri/tests/pass/concurrency/sync.rs
index 19ea6c130bd..3bd1e542407 100644
--- a/src/tools/miri/tests/pass/concurrency/sync.rs
+++ b/src/tools/miri/tests/pass/concurrency/sync.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance
 
 use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
diff --git a/src/tools/miri/tests/pass/concurrency/sync.stdout b/src/tools/miri/tests/pass/concurrency/sync.stack.stdout
index f2c036a1735..f2c036a1735 100644
--- a/src/tools/miri/tests/pass/concurrency/sync.stdout
+++ b/src/tools/miri/tests/pass/concurrency/sync.stack.stdout
diff --git a/src/tools/miri/tests/pass/concurrency/sync.tree.stdout b/src/tools/miri/tests/pass/concurrency/sync.tree.stdout
new file mode 100644
index 00000000000..f2c036a1735
--- /dev/null
+++ b/src/tools/miri/tests/pass/concurrency/sync.tree.stdout
@@ -0,0 +1,20 @@
+before wait
+before wait
+before wait
+before wait
+before wait
+before wait
+before wait
+before wait
+before wait
+before wait
+after wait
+after wait
+after wait
+after wait
+after wait
+after wait
+after wait
+after wait
+after wait
+after wait
diff --git a/src/tools/miri/tests/pass/concurrency/thread_locals.rs b/src/tools/miri/tests/pass/concurrency/thread_locals.rs
index b19e56312f3..13c11b55775 100644
--- a/src/tools/miri/tests/pass/concurrency/thread_locals.rs
+++ b/src/tools/miri/tests/pass/concurrency/thread_locals.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-strict-provenance
 
 //! The main purpose of this test is to check that if we take a pointer to
diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs
index 7ccafec6037..bd06eec9cd5 100644
--- a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs
+++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs
@@ -1,3 +1,6 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
+
 use std::cell::RefCell;
 use std::thread;
 
diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.stdout b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.stack.stdout
index b7877820a0c..b7877820a0c 100644
--- a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.stdout
+++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.stack.stdout
diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.tree.stdout b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.tree.stdout
new file mode 100644
index 00000000000..b7877820a0c
--- /dev/null
+++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.tree.stdout
@@ -0,0 +1,5 @@
+Dropping: 8 (should be before 'Continue main 1').
+Dropping: 8 (should be before 'Continue main 1').
+Continue main 1.
+Joining: 7 (should be before 'Continue main 2').
+Continue main 2.
diff --git a/src/tools/miri/tests/pass/disable-alignment-check.rs b/src/tools/miri/tests/pass/disable-alignment-check.rs
index 366aff4a9f8..fdcacc6cea4 100644
--- a/src/tools/miri/tests/pass/disable-alignment-check.rs
+++ b/src/tools/miri/tests/pass/disable-alignment-check.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-disable-alignment-check
 
 fn main() {
diff --git a/src/tools/miri/tests/pass/dyn-arbitrary-self.rs b/src/tools/miri/tests/pass/dyn-arbitrary-self.rs
index 256c72add92..94cf465e884 100644
--- a/src/tools/miri/tests/pass/dyn-arbitrary-self.rs
+++ b/src/tools/miri/tests/pass/dyn-arbitrary-self.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 #![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
 #![feature(rustc_attrs)]
 
diff --git a/src/tools/miri/tests/pass/extern_types.rs b/src/tools/miri/tests/pass/extern_types.rs
index aa4c65ea892..7ac93577f0c 100644
--- a/src/tools/miri/tests/pass/extern_types.rs
+++ b/src/tools/miri/tests/pass/extern_types.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance
 #![feature(extern_types)]
 
 extern "C" {
diff --git a/src/tools/miri/tests/pass/extern_types.stderr b/src/tools/miri/tests/pass/extern_types.stack.stderr
index 2e18f693058..2e18f693058 100644
--- a/src/tools/miri/tests/pass/extern_types.stderr
+++ b/src/tools/miri/tests/pass/extern_types.stack.stderr
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index ce62fb0de04..fee5ca44ffb 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -1,4 +1,5 @@
 #![feature(stmt_expr_attributes)]
+#![feature(round_ties_even)]
 #![allow(arithmetic_overflow)]
 use std::fmt::Debug;
 use std::hint::black_box;
@@ -9,6 +10,7 @@ fn main() {
     more_casts();
     ops();
     nan_casts();
+    rounding();
 }
 
 // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE.
@@ -553,3 +555,31 @@ fn nan_casts() {
     assert!(nan1_32.is_nan());
     assert!(nan2_32.is_nan());
 }
+
+fn rounding() {
+    // Test cases taken from the library's tests for this feature
+    // f32
+    assert_eq(2.5f32.round_ties_even(), 2.0f32);
+    assert_eq(1.0f32.round_ties_even(), 1.0f32);
+    assert_eq(1.3f32.round_ties_even(), 1.0f32);
+    assert_eq(1.5f32.round_ties_even(), 2.0f32);
+    assert_eq(1.7f32.round_ties_even(), 2.0f32);
+    assert_eq(0.0f32.round_ties_even(), 0.0f32);
+    assert_eq((-0.0f32).round_ties_even(), -0.0f32);
+    assert_eq((-1.0f32).round_ties_even(), -1.0f32);
+    assert_eq((-1.3f32).round_ties_even(), -1.0f32);
+    assert_eq((-1.5f32).round_ties_even(), -2.0f32);
+    assert_eq((-1.7f32).round_ties_even(), -2.0f32);
+    // f64
+    assert_eq(2.5f64.round_ties_even(), 2.0f64);
+    assert_eq(1.0f64.round_ties_even(), 1.0f64);
+    assert_eq(1.3f64.round_ties_even(), 1.0f64);
+    assert_eq(1.5f64.round_ties_even(), 2.0f64);
+    assert_eq(1.7f64.round_ties_even(), 2.0f64);
+    assert_eq(0.0f64.round_ties_even(), 0.0f64);
+    assert_eq((-0.0f64).round_ties_even(), -0.0f64);
+    assert_eq((-1.0f64).round_ties_even(), -1.0f64);
+    assert_eq((-1.3f64).round_ties_even(), -1.0f64);
+    assert_eq((-1.5f64).round_ties_even(), -2.0f64);
+    assert_eq((-1.7f64).round_ties_even(), -2.0f64);
+}
diff --git a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs b/src/tools/miri/tests/pass/future-self-referential.rs
index 6994def16a1..763eceeb6f0 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs
+++ b/src/tools/miri/tests/pass/future-self-referential.rs
@@ -1,3 +1,6 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
+
 use std::future::*;
 use std::marker::PhantomPinned;
 use std::pin::*;
diff --git a/src/tools/miri/tests/pass/generator.rs b/src/tools/miri/tests/pass/generator.rs
index 06f48666c55..e059c7114e3 100644
--- a/src/tools/miri/tests/pass/generator.rs
+++ b/src/tools/miri/tests/pass/generator.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 #![feature(generators, generator_trait, never_type)]
 
 use std::fmt::Debug;
diff --git a/src/tools/miri/tests/pass/hashmap.rs b/src/tools/miri/tests/pass/hashmap.rs
index 29ddd6c59a1..7224e357c6f 100644
--- a/src/tools/miri/tests/pass/hashmap.rs
+++ b/src/tools/miri/tests/pass/hashmap.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 use std::collections::HashMap;
 use std::hash::BuildHasher;
 
diff --git a/src/tools/miri/tests/pass/intptrcast.rs b/src/tools/miri/tests/pass/intptrcast.rs
index e7ff90cb6bf..42b6f433420 100644
--- a/src/tools/miri/tests/pass/intptrcast.rs
+++ b/src/tools/miri/tests/pass/intptrcast.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-permissive-provenance
 
 use std::mem;
diff --git a/src/tools/miri/tests/pass/linked-list.rs b/src/tools/miri/tests/pass/linked-list.rs
index 7377f9f60b0..36df30070cb 100644
--- a/src/tools/miri/tests/pass/linked-list.rs
+++ b/src/tools/miri/tests/pass/linked-list.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 #![feature(linked_list_cursors)]
 use std::collections::LinkedList;
 
diff --git a/src/tools/miri/tests/pass/many_shr_bor.rs b/src/tools/miri/tests/pass/many_shr_bor.rs
index 376b41dd6e2..aa960aa147a 100644
--- a/src/tools/miri/tests/pass/many_shr_bor.rs
+++ b/src/tools/miri/tests/pass/many_shr_bor.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 // Make sure validation can handle many overlapping shared borrows for different parts of a data structure
 use std::cell::RefCell;
 
diff --git a/src/tools/miri/tests/pass/memleak_ignored.rs b/src/tools/miri/tests/pass/memleak_ignored.rs
index 60e06094e17..bba3207ee4c 100644
--- a/src/tools/miri/tests/pass/memleak_ignored.rs
+++ b/src/tools/miri/tests/pass/memleak_ignored.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-ignore-leaks
 
 fn main() {
diff --git a/src/tools/miri/tests/pass/option_box_transmute_ptr.rs b/src/tools/miri/tests/pass/option_box_transmute_ptr.rs
index 0786db1ef89..0ba6607a5d4 100644
--- a/src/tools/miri/tests/pass/option_box_transmute_ptr.rs
+++ b/src/tools/miri/tests/pass/option_box_transmute_ptr.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 // This tests that the size of Option<Box<i32>> is the same as *const i32.
 fn option_box_deref() -> i32 {
     let val = Some(Box::new(42));
diff --git a/src/tools/miri/tests/pass/pointers.rs b/src/tools/miri/tests/pass/pointers.rs
index d1340a04e04..1525ded6151 100644
--- a/src/tools/miri/tests/pass/pointers.rs
+++ b/src/tools/miri/tests/pass/pointers.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-permissive-provenance
 #![feature(ptr_metadata, const_raw_ptr_comparison)]
 
diff --git a/src/tools/miri/tests/pass/provenance.rs b/src/tools/miri/tests/pass/provenance.rs
index c411f748a06..835daa36cfc 100644
--- a/src/tools/miri/tests/pass/provenance.rs
+++ b/src/tools/miri/tests/pass/provenance.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 #![feature(strict_provenance)]
 #![feature(pointer_byte_offsets)]
 use std::{mem, ptr};
diff --git a/src/tools/miri/tests/pass/ptr_int_casts.rs b/src/tools/miri/tests/pass/ptr_int_casts.rs
index 3044ac092b7..a2fcd098107 100644
--- a/src/tools/miri/tests/pass/ptr_int_casts.rs
+++ b/src/tools/miri/tests/pass/ptr_int_casts.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-permissive-provenance
 use std::mem;
 use std::ptr;
diff --git a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs
index ef7ff34d26b..35a52d0220b 100644
--- a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs
+++ b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-permissive-provenance
 #![feature(strict_provenance)]
 
diff --git a/src/tools/miri/tests/pass/ptr_int_transmute.rs b/src/tools/miri/tests/pass/ptr_int_transmute.rs
index ba50480c539..d99c25413e6 100644
--- a/src/tools/miri/tests/pass/ptr_int_transmute.rs
+++ b/src/tools/miri/tests/pass/ptr_int_transmute.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 // Test what happens when we read parts of a pointer.
 // Related to <https://github.com/rust-lang/rust/issues/69488>.
 fn ptr_partial_read() {
diff --git a/src/tools/miri/tests/pass/rc.rs b/src/tools/miri/tests/pass/rc.rs
index 569dbc459a5..6375abcd232 100644
--- a/src/tools/miri/tests/pass/rc.rs
+++ b/src/tools/miri/tests/pass/rc.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-strict-provenance
 #![feature(new_uninit)]
 #![feature(get_mut_unchecked)]
diff --git a/src/tools/miri/tests/pass/send-is-not-static-par-for.rs b/src/tools/miri/tests/pass/send-is-not-static-par-for.rs
index 642f75ecc09..458312508d2 100644
--- a/src/tools/miri/tests/pass/send-is-not-static-par-for.rs
+++ b/src/tools/miri/tests/pass/send-is-not-static-par-for.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 use std::sync::Mutex;
 
 fn par_for<I, F>(iter: I, f: F)
diff --git a/src/tools/miri/tests/pass/slices.rs b/src/tools/miri/tests/pass/slices.rs
index a56b97a5088..a99e921150b 100644
--- a/src/tools/miri/tests/pass/slices.rs
+++ b/src/tools/miri/tests/pass/slices.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-strict-provenance
 #![feature(new_uninit)]
 #![feature(slice_as_chunks)]
diff --git a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs b/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs
index 3ca937ae13d..74761a89cb9 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs
+++ b/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs
@@ -7,7 +7,7 @@ use std::{
 
 extern "Rust" {
     fn miri_get_alloc_id(ptr: *const u8) -> u64;
-    fn miri_print_borrow_stacks(alloc_id: u64);
+    fn miri_print_borrow_state(alloc_id: u64, show_unnamed: bool);
 }
 
 fn get_alloc_id(ptr: *const u8) -> u64 {
@@ -15,7 +15,9 @@ fn get_alloc_id(ptr: *const u8) -> u64 {
 }
 
 fn print_borrow_stacks(alloc_id: u64) {
-    unsafe { miri_print_borrow_stacks(alloc_id) }
+    unsafe {
+        miri_print_borrow_state(alloc_id, /* ignored: show_unnamed */ false)
+    }
 }
 
 fn main() {
diff --git a/src/tools/miri/tests/pass/threadleak_ignored.rs b/src/tools/miri/tests/pass/threadleak_ignored.rs
index a5f81573e96..d4899856194 100644
--- a/src/tools/miri/tests/pass/threadleak_ignored.rs
+++ b/src/tools/miri/tests/pass/threadleak_ignored.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-ignore-leaks
 
 //! Test that leaking threads works, and that their destructors are not executed.
diff --git a/src/tools/miri/tests/pass/threadleak_ignored.stderr b/src/tools/miri/tests/pass/threadleak_ignored.stack.stderr
index 7557f49c758..7557f49c758 100644
--- a/src/tools/miri/tests/pass/threadleak_ignored.stderr
+++ b/src/tools/miri/tests/pass/threadleak_ignored.stack.stderr
diff --git a/src/tools/miri/tests/pass/threadleak_ignored.tree.stderr b/src/tools/miri/tests/pass/threadleak_ignored.tree.stderr
new file mode 100644
index 00000000000..7557f49c758
--- /dev/null
+++ b/src/tools/miri/tests/pass/threadleak_ignored.tree.stderr
@@ -0,0 +1 @@
+Dropping 0
diff --git a/src/tools/miri/tests/pass/transmute_ptr.rs b/src/tools/miri/tests/pass/transmute_ptr.rs
index fd9d457e440..ce6d86b7068 100644
--- a/src/tools/miri/tests/pass/transmute_ptr.rs
+++ b/src/tools/miri/tests/pass/transmute_ptr.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 #![feature(strict_provenance)]
 use std::{mem, ptr};
 
diff --git a/src/tools/miri/tests/pass/tree-borrows/2phase-interiormut.rs b/src/tools/miri/tests/pass/tree-borrows/2phase-interiormut.rs
new file mode 100644
index 00000000000..af52f53791a
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/2phase-interiormut.rs
@@ -0,0 +1,27 @@
+//@compile-flags: -Zmiri-tree-borrows
+
+// Counterpart to tests/fail/tree-borrows/write-during-2phase.rs,
+// this is the opposite situation: the Write is not problematic because
+// the Protector has not yet been added and the Reserved has interior
+// mutability.
+use core::cell::Cell;
+
+trait Thing: Sized {
+    fn do_the_thing(&mut self, _s: i32) {}
+}
+impl<T> Thing for Cell<T> {}
+
+fn main() {
+    let mut x = Cell::new(1);
+    let l = &x;
+
+    x.do_the_thing({
+        // Several Foreign accesses (both Reads and Writes) to the location
+        // being reborrowed. Reserved + unprotected + interior mut
+        // makes the pointer immune to everything as long as all accesses
+        // are child accesses to its parent pointer x.
+        x.set(3);
+        l.set(4);
+        x.get() + l.get()
+    });
+}
diff --git a/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.rs b/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.rs
new file mode 100644
index 00000000000..1bd94c6df67
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.rs
@@ -0,0 +1,27 @@
+//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0
+#[path = "../../utils/mod.rs"]
+mod utils;
+use utils::macros::*;
+
+use std::cell::UnsafeCell;
+
+// UnsafeCells use the parent tag, so it is possible to use them with
+// few restrictions when only among themselves.
+fn main() {
+    unsafe {
+        let data = &mut UnsafeCell::new(0u8);
+        name!(data.get(), "data");
+        let x = &*data;
+        name!(x.get(), "x");
+        let y = &*data;
+        name!(y.get(), "y");
+        let alloc_id = alloc_id!(data.get());
+        print_state!(alloc_id);
+        // y and x tolerate alternating Writes
+        *y.get() = 1;
+        *x.get() = 2;
+        *y.get() = 3;
+        *x.get() = 4;
+        print_state!(alloc_id);
+    }
+}
diff --git a/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.stderr b/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.stderr
new file mode 100644
index 00000000000..d4bc822b4bb
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.stderr
@@ -0,0 +1,10 @@
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Re*|    └────<TAG=data,x,y>
+──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Act|    └────<TAG=data,x,y>
+──────────────────────────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree-borrows/copy-nonoverlapping.rs b/src/tools/miri/tests/pass/tree-borrows/copy-nonoverlapping.rs
new file mode 100644
index 00000000000..23250d6e6df
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/copy-nonoverlapping.rs
@@ -0,0 +1,29 @@
+//@compile-flags: -Zmiri-tree-borrows
+
+// copy_nonoverlapping works regardless of the order in which we construct
+// the arguments.
+pub fn main() {
+    test_to_from();
+    test_from_to();
+}
+
+fn test_to_from() {
+    unsafe {
+        let data = &mut [0u64, 1];
+        let to = data.as_mut_ptr().add(1);
+        let from = data.as_ptr();
+        std::ptr::copy_nonoverlapping(from, to, 1);
+    }
+}
+
+// Stacked Borrows would not have liked this one because the `as_mut_ptr` reborrow
+// invalidates the earlier pointer obtained from `as_ptr`, but Tree Borrows is fine
+// with it.
+fn test_from_to() {
+    unsafe {
+        let data = &mut [0u64, 1];
+        let from = data.as_ptr();
+        let to = data.as_mut_ptr().add(1);
+        std::ptr::copy_nonoverlapping(from, to, 1);
+    }
+}
diff --git a/src/tools/miri/tests/pass/tree-borrows/end-of-protector.rs b/src/tools/miri/tests/pass/tree-borrows/end-of-protector.rs
new file mode 100644
index 00000000000..76bbc73e662
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/end-of-protector.rs
@@ -0,0 +1,32 @@
+//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0
+
+// Check that a protector goes back to normal behavior when the function
+// returns.
+#[path = "../../utils/mod.rs"]
+mod utils;
+use utils::macros::*;
+
+fn main() {
+    unsafe {
+        let data = &mut 0u8;
+        name!(data);
+        let alloc_id = alloc_id!(data);
+        let x = &mut *data;
+        name!(x);
+        print_state!(alloc_id);
+        do_nothing(x); // creates then removes a Protector for a child of x
+        let y = &mut *data;
+        name!(y);
+        print_state!(alloc_id);
+        // Invalidates the previous reborrow, but its Protector has been removed.
+        *y = 1;
+        print_state!(alloc_id);
+    }
+}
+
+unsafe fn do_nothing(x: &mut u8) {
+    name!(x, "callee:x");
+    name!(x=>1, "caller:x");
+    let alloc_id = alloc_id!(x);
+    print_state!(alloc_id);
+}
diff --git a/src/tools/miri/tests/pass/tree-borrows/end-of-protector.stderr b/src/tools/miri/tests/pass/tree-borrows/end-of-protector.stderr
new file mode 100644
index 00000000000..d08d6948320
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/end-of-protector.stderr
@@ -0,0 +1,32 @@
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Res|    └─┬──<TAG=data>
+| Res|      └────<TAG=x>
+──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Res|    └─┬──<TAG=data>
+| Res|      └─┬──<TAG=x>
+| Res|        └─┬──<TAG=caller:x>
+| Res|          └────<TAG=callee:x> Strongly protected
+──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Res|    └─┬──<TAG=data>
+| Res|      ├─┬──<TAG=x>
+| Res|      │ └─┬──<TAG=caller:x>
+| Res|      │   └────<TAG=callee:x>
+| Res|      └────<TAG=y>
+──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Act|    └─┬──<TAG=data>
+| Dis|      ├─┬──<TAG=x>
+| Dis|      │ └─┬──<TAG=caller:x>
+| Dis|      │   └────<TAG=callee:x>
+| Act|      └────<TAG=y>
+──────────────────────────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree-borrows/formatting.rs b/src/tools/miri/tests/pass/tree-borrows/formatting.rs
new file mode 100644
index 00000000000..9021c417638
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/formatting.rs
@@ -0,0 +1,73 @@
+//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0
+
+#[path = "../../utils/mod.rs"]
+mod utils;
+use utils::macros::*;
+
+// Check the formatting of the trees.
+fn main() {
+    unsafe {
+        alignment_check();
+        structure_check();
+    }
+}
+
+// Alignment check: we split the array at indexes with different amounts of
+// decimal digits to verify proper padding.
+unsafe fn alignment_check() {
+    let data: &mut [u8] = &mut [0; 1024];
+    name!(data.as_ptr()=>2, "data");
+    let alloc_id = alloc_id!(data.as_ptr());
+    let x = &mut data[1];
+    name!(x as *mut _, "data[1]");
+    *x = 1;
+    let x = &mut data[10];
+    name!(x as *mut _, "data[10]");
+    *x = 1;
+    let x = &mut data[100];
+    name!(x as *mut _, "data[100]");
+    *x = 1;
+    let _val = data[100]; // So that the above is Frz
+    let x = &mut data[1000];
+    name!(x as *mut _, "data[1000]");
+    *x = 1;
+    print_state!(alloc_id);
+}
+
+// Tree structure check: somewhat complex organization of reborrows.
+unsafe fn structure_check() {
+    let x = &0u8;
+    name!(x);
+    let xa = &*x;
+    name!(xa);
+    let xb = &*x;
+    name!(xb);
+    let xc = &*x;
+    name!(xc);
+    let xaa = &*xa;
+    name!(xaa);
+    let xab = &*xa;
+    name!(xab);
+    let xba = &*xb;
+    name!(xba);
+    let xbaa = &*xba;
+    name!(xbaa);
+    let xbaaa = &*xbaa;
+    name!(xbaaa);
+    let xbaaaa = &*xbaaa;
+    name!(xbaaaa);
+    let xca = &*xc;
+    name!(xca);
+    let xcb = &*xc;
+    name!(xcb);
+    let xcaa = &*xca;
+    name!(xcaa);
+    let xcab = &*xca;
+    name!(xcab);
+    let xcba = &*xcb;
+    name!(xcba);
+    let xcbb = &*xcb;
+    name!(xcbb);
+    let alloc_id = alloc_id!(x);
+    print_state!(alloc_id);
+}
diff --git a/src/tools/miri/tests/pass/tree-borrows/formatting.stderr b/src/tools/miri/tests/pass/tree-borrows/formatting.stderr
new file mode 100644
index 00000000000..a59775cf21f
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/formatting.stderr
@@ -0,0 +1,29 @@
+─────────────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1..  2.. 10.. 11..100..101..1000..1001..1024
+| Res| Act| Res| Act| Res| Act|  Res|  Act|  Res|    └─┬──<TAG=data>
+|----| Act|----|?Dis|----|?Dis| ----| ?Dis| ----|      ├────<TAG=data[1]>
+|----|----|----| Act|----|?Dis| ----| ?Dis| ----|      ├────<TAG=data[10]>
+|----|----|----|----|----| Frz| ----| ?Dis| ----|      ├────<TAG=data[100]>
+|----|----|----|----|----|----| ----|  Act| ----|      └────<TAG=data[1000]>
+─────────────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Frz|    └─┬──<TAG=x>
+| Frz|      ├─┬──<TAG=xa>
+| Frz|      │ ├────<TAG=xaa>
+| Frz|      │ └────<TAG=xab>
+| Frz|      ├─┬──<TAG=xb>
+| Frz|      │ └─┬──<TAG=xba>
+| Frz|      │   └─┬──<TAG=xbaa>
+| Frz|      │     └─┬──<TAG=xbaaa>
+| Frz|      │       └────<TAG=xbaaaa>
+| Frz|      └─┬──<TAG=xc>
+| Frz|        ├─┬──<TAG=xca>
+| Frz|        │ ├────<TAG=xcaa>
+| Frz|        │ └────<TAG=xcab>
+| Frz|        └─┬──<TAG=xcb>
+| Frz|          ├────<TAG=xcba>
+| Frz|          └────<TAG=xcbb>
+──────────────────────────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree-borrows/read-only-from-mut.rs b/src/tools/miri/tests/pass/tree-borrows/read-only-from-mut.rs
new file mode 100644
index 00000000000..4daf06c777e
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/read-only-from-mut.rs
@@ -0,0 +1,14 @@
+//@compile-flags: -Zmiri-tree-borrows
+
+// Tree Borrows has no issue with several mutable references existing
+// at the same time, as long as they are used only immutably.
+// I.e. multiple Reserved can coexist.
+pub fn main() {
+    unsafe {
+        let base = &mut 42u64;
+        let r1 = &mut *(base as *mut u64);
+        let r2 = &mut *(base as *mut u64);
+        let _l = *r1;
+        let _l = *r2;
+    }
+}
diff --git a/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.rs b/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.rs
new file mode 100644
index 00000000000..e3f3f2d4032
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.rs
@@ -0,0 +1,24 @@
+//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0
+
+#[path = "../../utils/mod.rs"]
+mod utils;
+use utils::macros::*;
+
+// To check that a reborrow is counted as a Read access, we use a reborrow
+// with no additional Read to Freeze an Active pointer.
+
+fn main() {
+    unsafe {
+        let parent = &mut 0u8;
+        name!(parent);
+        let alloc_id = alloc_id!(parent);
+        let x = &mut *parent;
+        name!(x);
+        *x = 0; // x is now Active
+        print_state!(alloc_id);
+        let y = &mut *parent;
+        name!(y);
+        // Check in the debug output that x has been Frozen by the reborrow
+        print_state!(alloc_id);
+    }
+}
diff --git a/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.stderr b/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.stderr
new file mode 100644
index 00000000000..b9c52c20640
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.stderr
@@ -0,0 +1,13 @@
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Act|    └─┬──<TAG=parent>
+| Act|      └────<TAG=x>
+──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Act|    └─┬──<TAG=parent>
+| Frz|      ├────<TAG=x>
+| Res|      └────<TAG=y>
+──────────────────────────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree-borrows/reserved.rs b/src/tools/miri/tests/pass/tree-borrows/reserved.rs
new file mode 100644
index 00000000000..d8a8c27568d
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/reserved.rs
@@ -0,0 +1,127 @@
+//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0
+
+#[path = "../../utils/mod.rs"]
+mod utils;
+use utils::macros::*;
+use utils::miri_extern::miri_write_to_stderr;
+
+use std::cell::UnsafeCell;
+
+// We exhaustively check that Reserved behaves as we want under all of the
+// following conditions:
+// - with or without interior mutability
+// - with or without a protector
+// - for a foreign read or write
+// Of these cases, those in this file are the ones that must not cause
+// immediate UB, and those that do are in tests/fail/tree-borrows/reserved/
+// and are the combinations [_ + protected + write]
+
+fn main() {
+    unsafe {
+        cell_protected_read();
+        cell_unprotected_read();
+        cell_unprotected_write();
+        int_protected_read();
+        int_unprotected_read();
+        int_unprotected_write();
+    }
+}
+
+unsafe fn print(msg: &str) {
+    miri_write_to_stderr(msg.as_bytes());
+    miri_write_to_stderr("\n".as_bytes());
+}
+
+unsafe fn read_second<T>(x: &mut T, y: *mut u8) {
+    name!(x as *mut T as *mut u8=>1, "caller:x");
+    name!(x as *mut T as *mut u8, "callee:x");
+    name!(y, "caller:y");
+    name!(y, "callee:y");
+    let _val = *y;
+}
+
+// Foreign Read on a interior mutable Protected Reserved turns it Frozen.
+unsafe fn cell_protected_read() {
+    print("[interior mut + protected] Foreign Read: Re* -> Frz");
+    let base = &mut UnsafeCell::new(0u8);
+    name!(base.get(), "base");
+    let alloc_id = alloc_id!(base.get());
+    let x = &mut *(base as *mut UnsafeCell<u8>);
+    name!(x.get(), "x");
+    let y = (&mut *base).get();
+    name!(y);
+    read_second(x, y); // Foreign Read for callee:x
+    print_state!(alloc_id);
+}
+
+// Foreign Read on an interior mutable pointer is a noop.
+unsafe fn cell_unprotected_read() {
+    print("[interior mut] Foreign Read: Re* -> Re*");
+    let base = &mut UnsafeCell::new(0u64);
+    name!(base.get(), "base");
+    let alloc_id = alloc_id!(base.get());
+    let x = &mut *(base as *mut UnsafeCell<_>);
+    name!(x.get(), "x");
+    let y = (&mut *base).get();
+    name!(y);
+    let _val = *y; // Foreign Read for x
+    print_state!(alloc_id);
+}
+
+// Foreign Write on an interior mutable pointer is a noop.
+// Also y must become Active.
+unsafe fn cell_unprotected_write() {
+    print("[interior mut] Foreign Write: Re* -> Re*");
+    let base = &mut UnsafeCell::new(0u64);
+    name!(base.get(), "base");
+    let alloc_id = alloc_id!(base.get());
+    let x = &mut *(base as *mut UnsafeCell<u64>);
+    name!(x.get(), "x");
+    let y = (&mut *base).get();
+    name!(y);
+    *y = 1; // Foreign Write for x
+    print_state!(alloc_id);
+}
+
+// Foreign Read on a Protected Reserved turns it Frozen.
+unsafe fn int_protected_read() {
+    print("[protected] Foreign Read: Res -> Frz");
+    let base = &mut 0u8;
+    let alloc_id = alloc_id!(base);
+    name!(base);
+    let x = &mut *(base as *mut u8);
+    name!(x);
+    let y = (&mut *base) as *mut u8;
+    name!(y);
+    read_second(x, y); // Foreign Read for callee:x
+    print_state!(alloc_id);
+}
+
+// Foreign Read on a Reserved is a noop.
+// Also y must become Active.
+unsafe fn int_unprotected_read() {
+    print("[] Foreign Read: Res -> Res");
+    let base = &mut 0u8;
+    name!(base);
+    let alloc_id = alloc_id!(base);
+    let x = &mut *(base as *mut u8);
+    name!(x);
+    let y = (&mut *base) as *mut u8;
+    name!(y);
+    let _val = *y; // Foreign Read for x
+    print_state!(alloc_id);
+}
+
+// Foreign Write on a Reserved turns it Disabled.
+unsafe fn int_unprotected_write() {
+    print("[] Foreign Write: Res -> Dis");
+    let base = &mut 0u8;
+    name!(base);
+    let alloc_id = alloc_id!(base);
+    let x = &mut *(base as *mut u8);
+    name!(x);
+    let y = (&mut *base) as *mut u8;
+    name!(y);
+    *y = 1; // Foreign Write for x
+    print_state!(alloc_id);
+}
diff --git a/src/tools/miri/tests/pass/tree-borrows/reserved.stderr b/src/tools/miri/tests/pass/tree-borrows/reserved.stderr
new file mode 100644
index 00000000000..d76ee0f8266
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/reserved.stderr
@@ -0,0 +1,52 @@
+[interior mut + protected] Foreign Read: Re* -> Frz
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Re*|    └─┬──<TAG=base>
+| Re*|      ├─┬──<TAG=x>
+| Re*|      │ └─┬──<TAG=caller:x>
+| Frz|      │   └────<TAG=callee:x>
+| Re*|      └────<TAG=y,caller:y,callee:y>
+──────────────────────────────────────────────────────────────────────
+[interior mut] Foreign Read: Re* -> Re*
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  8
+| Re*|    └─┬──<TAG=base>
+| Re*|      ├────<TAG=x>
+| Re*|      └────<TAG=y>
+──────────────────────────────────────────────────────────────────────
+[interior mut] Foreign Write: Re* -> Re*
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  8
+| Act|    └─┬──<TAG=base>
+| Re*|      ├────<TAG=x>
+| Act|      └────<TAG=y>
+──────────────────────────────────────────────────────────────────────
+[protected] Foreign Read: Res -> Frz
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Res|    └─┬──<TAG=base>
+| Res|      ├─┬──<TAG=x>
+| Res|      │ └─┬──<TAG=caller:x>
+| Frz|      │   └────<TAG=callee:x>
+| Res|      └────<TAG=y,caller:y,callee:y>
+──────────────────────────────────────────────────────────────────────
+[] Foreign Read: Res -> Res
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Res|    └─┬──<TAG=base>
+| Res|      ├────<TAG=x>
+| Res|      └────<TAG=y>
+──────────────────────────────────────────────────────────────────────
+[] Foreign Write: Res -> Dis
+──────────────────────────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..  1
+| Act|    └─┬──<TAG=base>
+| Dis|      ├────<TAG=x>
+| Act|      └────<TAG=y>
+──────────────────────────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree-borrows/transmute-unsafecell.rs b/src/tools/miri/tests/pass/tree-borrows/transmute-unsafecell.rs
new file mode 100644
index 00000000000..e1a9334ab54
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree-borrows/transmute-unsafecell.rs
@@ -0,0 +1,13 @@
+//@compile-flags: -Zmiri-tree-borrows
+
+use core::cell::UnsafeCell;
+use core::mem;
+
+fn main() {
+    unsafe {
+        let x = &0i32;
+        // As long as we only read, transmuting this to UnsafeCell should be fine.
+        let cell_x: &UnsafeCell<i32> = mem::transmute(&x);
+        let _val = *cell_x.get();
+    }
+}
diff --git a/src/tools/miri/tests/pass/unsized.rs b/src/tools/miri/tests/pass/unsized.rs
index d9beac4327d..c9046dc3c76 100644
--- a/src/tools/miri/tests/pass/unsized.rs
+++ b/src/tools/miri/tests/pass/unsized.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 #![feature(unsized_tuple_coercion)]
 #![feature(unsized_fn_params)]
 
diff --git a/src/tools/miri/tests/pass/vec.rs b/src/tools/miri/tests/pass/vec.rs
index 30a28bc5803..06ec2f99172 100644
--- a/src/tools/miri/tests/pass/vec.rs
+++ b/src/tools/miri/tests/pass/vec.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-strict-provenance
 #![feature(iter_advance_by, iter_next_chunk)]
 
diff --git a/src/tools/miri/tests/pass/vecdeque.rs b/src/tools/miri/tests/pass/vecdeque.rs
index 6f56f9d103e..dfbf9bb83c1 100644
--- a/src/tools/miri/tests/pass/vecdeque.rs
+++ b/src/tools/miri/tests/pass/vecdeque.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-strict-provenance
 use std::collections::VecDeque;
 
diff --git a/src/tools/miri/tests/pass/vecdeque.stdout b/src/tools/miri/tests/pass/vecdeque.stack.stdout
index 63de960ee2b..63de960ee2b 100644
--- a/src/tools/miri/tests/pass/vecdeque.stdout
+++ b/src/tools/miri/tests/pass/vecdeque.stack.stdout
diff --git a/src/tools/miri/tests/pass/vecdeque.tree.stdout b/src/tools/miri/tests/pass/vecdeque.tree.stdout
new file mode 100644
index 00000000000..63de960ee2b
--- /dev/null
+++ b/src/tools/miri/tests/pass/vecdeque.tree.stdout
@@ -0,0 +1,2 @@
+[2, 2] Iter([2, 2], [])
+Iter([], [])
diff --git a/src/tools/miri/tests/utils/macros.rs b/src/tools/miri/tests/utils/macros.rs
new file mode 100644
index 00000000000..de223410fba
--- /dev/null
+++ b/src/tools/miri/tests/utils/macros.rs
@@ -0,0 +1,61 @@
+#![allow(unused_macros)]
+#![allow(unused_macro_rules)]
+#![allow(unused_imports)]
+
+/// `alloc_id!(ptr)`: obtain the allocation id from a pointer.
+///
+/// `ptr` should be any pointer or reference that can be converted with `_ as *const u8`.
+///
+/// The id obtained can be passed directly to `print_state!`.
+macro_rules! alloc_id {
+    ($ptr:expr) => {
+        crate::utils::miri_extern::miri_get_alloc_id($ptr as *const u8 as *const ())
+    };
+}
+
+/// `print_state!(alloc_id, show_unnamed)`: print the internal state of the borrow
+/// tracker (stack or tree).
+///
+/// `alloc_id` should be obtained from `alloc_id!`.
+///
+/// `show_unnamed` is an optional boolean that determines if Tree Borrows displays
+/// tags that have not been given a name. Defaults to `false`.
+macro_rules! print_state {
+    ($alloc_id:expr) => {
+        crate::utils::macros::print_state!($alloc_id, false);
+    };
+    ($alloc_id:expr, $show:expr) => {
+        crate::utils::miri_extern::miri_print_borrow_state($alloc_id, $show);
+    };
+}
+
+/// `name!(ptr => nth_parent, name)`: associate `name` to the `nth_parent` of `ptr`.
+///
+/// `ptr` should be any pointer or reference that can be converted with `_ as *const u8`.
+///
+/// `nth_parent` is an optional `u8` that defaults to 0. The corresponding ancestor
+/// of the tag of `ptr` will be searched: 0 for `ptr` itself, 1 for the direct parent
+/// of `ptr`, 2 for the grandparent, etc. If `nth_parent` is not specified,
+/// then `=>` should also not be included.
+///
+/// `name` is an optional string that will be used as the name. Defaults to
+/// `stringify!($ptr)` the name of `ptr` in the source code.
+macro_rules! name {
+    ($ptr:expr, $name:expr) => {
+        crate::utils::macros::name!($ptr => 0, $name);
+    };
+    ($ptr:expr) => {
+        crate::utils::macros::name!($ptr => 0, stringify!($ptr));
+    };
+    ($ptr:expr => $nb:expr) => {
+        crate::utils::macros::name!($ptr => $nb, stringify!($ptr));
+    };
+    ($ptr:expr => $nb:expr, $name:expr) => {
+        let name = $name.as_bytes();
+        crate::utils::miri_extern::miri_pointer_name($ptr as *const u8 as *const (), $nb, name);
+    };
+}
+
+pub(crate) use alloc_id;
+pub(crate) use name;
+pub(crate) use print_state;
diff --git a/src/tools/miri/tests/utils/miri_extern.rs b/src/tools/miri/tests/utils/miri_extern.rs
new file mode 100644
index 00000000000..6c4298c613b
--- /dev/null
+++ b/src/tools/miri/tests/utils/miri_extern.rs
@@ -0,0 +1,142 @@
+#![allow(dead_code)]
+
+#[repr(C)]
+/// Layout of the return value of `miri_resolve_frame`,
+/// with fields in the exact same order.
+pub struct MiriFrame {
+    // The size of the name of the function being executed, encoded in UTF-8
+    pub name_len: usize,
+    // The size of filename of the function being executed, encoded in UTF-8
+    pub filename_len: usize,
+    // The line number currently being executed in `filename`, starting from '1'.
+    pub lineno: u32,
+    // The column number currently being executed in `filename`, starting from '1'.
+    pub colno: u32,
+    // The function pointer to the function currently being executed.
+    // This can be compared against function pointers obtained by
+    // casting a function (e.g. `my_fn as *mut ()`)
+    pub fn_ptr: *mut (),
+}
+
+#[cfg(miri)]
+extern "Rust" {
+    /// Miri-provided extern function to mark the block `ptr` points to as a "root"
+    /// for some static memory. This memory and everything reachable by it is not
+    /// considered leaking even if it still exists when the program terminates.
+    ///
+    /// `ptr` has to point to the beginning of an allocated block.
+    pub fn miri_static_root(ptr: *const u8);
+
+    // Miri-provided extern function to get the amount of frames in the current backtrace.
+    // The `flags` argument must be `0`.
+    pub fn miri_backtrace_size(flags: u64) -> usize;
+
+    /// Miri-provided extern function to obtain a backtrace of the current call stack.
+    /// This writes a slice of pointers into `buf` - each pointer is an opaque value
+    /// that is only useful when passed to `miri_resolve_frame`.
+    /// `buf` must have `miri_backtrace_size(0) * pointer_size` bytes of space.
+    /// The `flags` argument must be `1`.
+    pub fn miri_get_backtrace(flags: u64, buf: *mut *mut ());
+
+    /// Miri-provided extern function to resolve a frame pointer obtained
+    /// from `miri_get_backtrace`. The `flags` argument must be `1`.
+    ///
+    /// This function can be called on any thread (not just the one which obtained `frame`).
+    pub fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame;
+
+    /// Miri-provided extern function to get the name and filename of the frame provided by `miri_resolve_frame`.
+    /// `name_buf` and `filename_buf` should be allocated with the `name_len` and `filename_len` fields of `MiriFrame`.
+    /// The flags argument must be `0`.
+    pub fn miri_resolve_frame_names(
+        ptr: *mut (),
+        flags: u64,
+        name_buf: *mut u8,
+        filename_buf: *mut u8,
+    );
+
+    /// Miri-provided extern function to begin unwinding with the given payload.
+    ///
+    /// This is internal and unstable and should not be used; we give it here
+    /// just to be complete.
+    pub fn miri_start_panic(payload: *mut u8) -> !;
+
+    /// Miri-provided extern function to get the internal unique identifier for the allocation that a pointer
+    /// points to. If this pointer is invalid (not pointing to an allocation), interpretation will abort.
+    ///
+    /// This is only useful as an input to `miri_print_borrow_stacks`, and it is a separate call because
+    /// getting a pointer to an allocation at runtime can change the borrow stacks in the allocation.
+    /// This function should be considered unstable. It exists only to support `miri_print_borrow_stacks` and so
+    /// inherits all of its instability.
+    pub fn miri_get_alloc_id(ptr: *const ()) -> u64;
+
+    /// Miri-provided extern function to print (from the interpreter, not the program) the contents of all
+    /// borrows in an allocation.
+    ///
+    /// If Stacked Borrows is running, this prints all the stacks. The leftmost tag is the bottom of the stack.
+    ///
+    /// If Tree borrows is running, this prints on the left the permissions of each tag on each range,
+    /// an on the right the tree structure of the tags. If some tags were named via `miri_pointer_name`,
+    /// their names appear here.
+    ///
+    /// If additionally `show_unnamed` is `false` then tags that did *not* receive a name will be hidden.
+    /// Ensure that either the important tags have been named, or `show_unnamed = true`.
+    /// Note: as Stacked Borrows does not have tag names at all, `show_unnamed` is ignored and all tags are shown.
+    /// In general, unless you strongly want some tags to be hidden (as is the case in `tree-borrows` tests),
+    /// `show_unnamed = true` should be the default.
+    ///
+    /// The format of what this emits is unstable and may change at any time. In particular, users should be
+    /// aware that Miri will periodically attempt to garbage collect the contents of all stacks. Callers of
+    /// this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC.
+    ///
+    /// This function is extremely unstable. At any time the format of its output may change, its signature may
+    /// change, or it may be removed entirely.
+    pub fn miri_print_borrow_state(alloc_id: u64, show_unnamed: bool);
+
+    /// Miri-provided extern function to associate a name to the nth parent of a tag.
+    /// Typically the name given would be the name of the program variable that holds the pointer.
+    /// Unreachable tags can still be named by using nonzero `nth_parent` and a child tag.
+    ///
+    /// This function does nothing under Stacked Borrows, since Stacked Borrows's implementation
+    /// of `miri_print_borrow_state` does not show the names.
+    ///
+    /// Under Tree Borrows, the names also appear in error messages.
+    pub fn miri_pointer_name(ptr: *const (), nth_parent: u8, name: &[u8]);
+
+    /// Miri-provided extern function to print (from the interpreter, not the
+    /// program) the contents of a section of program memory, as bytes. Bytes
+    /// written using this function will emerge from the interpreter's stdout.
+    pub fn miri_write_to_stdout(bytes: &[u8]);
+
+    /// Miri-provided extern function to print (from the interpreter, not the
+    /// program) the contents of a section of program memory, as bytes. Bytes
+    /// written using this function will emerge from the interpreter's stderr.
+    pub fn miri_write_to_stderr(bytes: &[u8]);
+
+    /// Miri-provided extern function to allocate memory from the interpreter.
+    ///
+    /// This is useful when no fundamental way of allocating memory is
+    /// available, e.g. when using `no_std` + `alloc`.
+    pub fn miri_alloc(size: usize, align: usize) -> *mut u8;
+
+    /// Miri-provided extern function to deallocate memory.
+    pub fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
+
+    /// Convert a path from the host Miri runs on to the target Miri interprets.
+    /// Performs conversion of path separators as needed.
+    ///
+    /// Usually Miri performs this kind of conversion automatically. However, manual conversion
+    /// might be necessary when reading an environment variable that was set on the host
+    /// (such as TMPDIR) and using it as a target path.
+    ///
+    /// Only works with isolation disabled.
+    ///
+    /// `in` must point to a null-terminated string, and will be read as the input host path.
+    /// `out` must point to at least `out_size` many bytes, and the result will be stored there
+    /// with a null terminator.
+    /// Returns 0 if the `out` buffer was large enough, and the required size otherwise.
+    pub fn miri_host_to_target_path(
+        path: *const std::ffi::c_char,
+        out: *mut std::ffi::c_char,
+        out_size: usize,
+    ) -> usize;
+}
diff --git a/src/tools/miri/tests/utils/mod.rs b/src/tools/miri/tests/utils/mod.rs
new file mode 100644
index 00000000000..e1ea77e4df8
--- /dev/null
+++ b/src/tools/miri/tests/utils/mod.rs
@@ -0,0 +1,2 @@
+pub mod macros;
+pub mod miri_extern;
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index fc77515b63b..25242c6028a 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -169,9 +169,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.88.0"
+version = "0.89.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4df80a3fbc1f0e59f560eeeebca94bf655566a8ad3023c210a109deb6056455a"
+checksum = "ea176c50987dc4765961aa165001e8eb5a722a26308c5797a47303ea91686aab"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -181,9 +181,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.88.0"
+version = "0.89.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f39e5272016916956298cceea5147006f897972c274a768ed4d6e074efe5d3fb"
+checksum = "473b480241695428c14e8f84f1c9a47ef232450a50faf3a4041e5c9dc11e0a3b"
 dependencies = [
  "bitflags",
  "chalk-derive",
@@ -192,9 +192,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-recursive"
-version = "0.88.0"
+version = "0.89.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9d60b42ad7478d3e027e2f9ea4e99fbbb8fdee0c8c3cf068be269f57e603618"
+checksum = "6764b4fe67cac3a3758185084efbfbd39bf0352795824ba849ddd2b64cd4bb28"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -205,9 +205,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.88.0"
+version = "0.89.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab30620ea5b36819525eaab2204f4b8e1842fc7ee36826424a28bef59ae7fecf"
+checksum = "55a7e6160966eceb6e7dcc2f479a2af4c477aaf5bccbc640d82515995ab1a6cc"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
diff --git a/src/tools/rust-analyzer/bench_data/numerous_macro_rules b/src/tools/rust-analyzer/bench_data/numerous_macro_rules
index bf89ed594f7..7610a3ae1e3 100644
--- a/src/tools/rust-analyzer/bench_data/numerous_macro_rules
+++ b/src/tools/rust-analyzer/bench_data/numerous_macro_rules
@@ -341,8 +341,8 @@ macro_rules! __ra_macro_fixture339 {($name :  ident )=>{ impl  Clone  for $name
 macro_rules! __ra_macro_fixture340 {([$($stack :  tt )*])=>{$($stack )* }; ([$($stack :  tt )*]{$($tail :  tt )* })=>{$($stack )* { remove_sections_inner ! ([]$($tail )*); }}; ([$($stack :  tt )*]$t :  tt $($tail :  tt )*)=>{ remove_sections ! ([$($stack )* $t ]$($tail )*); }; }
 macro_rules! __ra_macro_fixture341 {($t :  ty ,$z :  expr )=>{ impl  Zero  for $t { fn  zero ()->  Self {$z  as $t } fn  is_zero (&  self )->  bool { self == &  Self ::  zero ()}}}; }
 macro_rules! __ra_macro_fixture342 {($($ident :  ident ),* $(,)?)=>{$(# [ allow ( bad_style )] pub  const $ident :  super ::  Name =  super ::  Name ::  new_inline ( stringify ! ($ident )); )* }; }
-macro_rules! __ra_macro_fixture343 {($($trait :  ident =>$expand :  ident ),* )=>{# [ derive ( Debug ,  Clone ,  Copy ,  PartialEq ,  Eq ,  Hash )] pub  enum  BuiltinDeriveExpander {$($trait ),* } impl  BuiltinDeriveExpander { pub  fn  expand (&  self ,  db : &  dyn  AstDatabase ,  id :  LazyMacroId ,  tt : &  tt ::  Subtree , )->  Result <  tt ::  Subtree ,  mbe ::  ExpandError > { let  expander =  match *  self {$(BuiltinDeriveExpander ::$trait =>$expand , )* };  expander ( db ,  id ,  tt )} fn  find_by_name ( name : &  name ::  Name )->  Option <  Self > { match  name {$(id  if  id == &  name ::  name ! [$trait ]=> Some ( BuiltinDeriveExpander ::$trait ), )* _ => None , }}}}; }
-macro_rules! __ra_macro_fixture344 {( LAZY : $(($name :  ident , $kind :  ident )=>$expand :  ident ),* ,  EAGER : $(($e_name :  ident , $e_kind :  ident )=>$e_expand :  ident ),* )=>{# [ derive ( Debug ,  Clone ,  Copy ,  PartialEq ,  Eq ,  Hash )] pub  enum  BuiltinFnLikeExpander {$($kind ),* }# [ derive ( Debug ,  Clone ,  Copy ,  PartialEq ,  Eq ,  Hash )] pub  enum  EagerExpander {$($e_kind ),* } impl  BuiltinFnLikeExpander { pub  fn  expand (&  self ,  db : &  dyn  AstDatabase ,  id :  LazyMacroId ,  tt : &  tt ::  Subtree , )->  ExpandResult <  tt ::  Subtree > { let  expander =  match *  self {$(BuiltinFnLikeExpander ::$kind =>$expand , )* };  expander ( db ,  id ,  tt )}} impl  EagerExpander { pub  fn  expand (&  self ,  db : &  dyn  AstDatabase ,  arg_id :  EagerMacroId ,  tt : &  tt ::  Subtree , )->  ExpandResult <  Option < ( tt ::  Subtree ,  FragmentKind )>> { let  expander =  match *  self {$(EagerExpander ::$e_kind =>$e_expand , )* };  expander ( db ,  arg_id ,  tt )}} fn  find_by_name ( ident : &  name ::  Name )->  Option <  Either <  BuiltinFnLikeExpander ,  EagerExpander >> { match  ident {$(id  if  id == &  name ::  name ! [$name ]=> Some ( Either ::  Left ( BuiltinFnLikeExpander ::$kind )), )* $(id  if  id == &  name ::  name ! [$e_name ]=> Some ( Either ::  Right ( EagerExpander ::$e_kind )), )* _ => return  None , }}}; }
+macro_rules! __ra_macro_fixture343 {($($trait :  ident =>$expand :  ident ),* )=>{# [ derive ( Debug ,  Clone ,  Copy ,  PartialEq ,  Eq ,  Hash )] pub  enum  BuiltinDeriveExpander {$($trait ),* } impl  BuiltinDeriveExpander { pub  fn  expand (&  self ,  db : &  dyn  ExpandDatabase ,  id :  LazyMacroId ,  tt : &  tt ::  Subtree , )->  Result <  tt ::  Subtree ,  mbe ::  ExpandError > { let  expander =  match *  self {$(BuiltinDeriveExpander ::$trait =>$expand , )* };  expander ( db ,  id ,  tt )} fn  find_by_name ( name : &  name ::  Name )->  Option <  Self > { match  name {$(id  if  id == &  name ::  name ! [$trait ]=> Some ( BuiltinDeriveExpander ::$trait ), )* _ => None , }}}}; }
+macro_rules! __ra_macro_fixture344 {( LAZY : $(($name :  ident , $kind :  ident )=>$expand :  ident ),* ,  EAGER : $(($e_name :  ident , $e_kind :  ident )=>$e_expand :  ident ),* )=>{# [ derive ( Debug ,  Clone ,  Copy ,  PartialEq ,  Eq ,  Hash )] pub  enum  BuiltinFnLikeExpander {$($kind ),* }# [ derive ( Debug ,  Clone ,  Copy ,  PartialEq ,  Eq ,  Hash )] pub  enum  EagerExpander {$($e_kind ),* } impl  BuiltinFnLikeExpander { pub  fn  expand (&  self ,  db : &  dyn  ExpandDatabase ,  id :  LazyMacroId ,  tt : &  tt ::  Subtree , )->  ExpandResult <  tt ::  Subtree > { let  expander =  match *  self {$(BuiltinFnLikeExpander ::$kind =>$expand , )* };  expander ( db ,  id ,  tt )}} impl  EagerExpander { pub  fn  expand (&  self ,  db : &  dyn  ExpandDatabase ,  arg_id :  EagerMacroId ,  tt : &  tt ::  Subtree , )->  ExpandResult <  Option < ( tt ::  Subtree ,  FragmentKind )>> { let  expander =  match *  self {$(EagerExpander ::$e_kind =>$e_expand , )* };  expander ( db ,  arg_id ,  tt )}} fn  find_by_name ( ident : &  name ::  Name )->  Option <  Either <  BuiltinFnLikeExpander ,  EagerExpander >> { match  ident {$(id  if  id == &  name ::  name ! [$name ]=> Some ( Either ::  Left ( BuiltinFnLikeExpander ::$kind )), )* $(id  if  id == &  name ::  name ! [$e_name ]=> Some ( Either ::  Right ( EagerExpander ::$e_kind )), )* _ => return  None , }}}; }
 macro_rules! __ra_macro_fixture345 {($($ty :  ty =>$this :  ident $im :  block );*)=>{$(impl  ToTokenTree  for $ty { fn  to_token ($this )->  tt ::  TokenTree { let  leaf :  tt ::  Leaf = $im .  into ();  leaf .  into ()}} impl  ToTokenTree  for &$ty { fn  to_token ($this )->  tt ::  TokenTree { let  leaf :  tt ::  Leaf = $im .  clone ().  into ();  leaf .  into ()}})* }}
 macro_rules! __ra_macro_fixture346 {($name :  ident )=>{ impl $crate ::  salsa ::  InternKey  for $name { fn  from_intern_id ( v : $crate ::  salsa ::  InternId )->  Self {$name ( v )} fn  as_intern_id (&  self )-> $crate ::  salsa ::  InternId { self .  0 }}}; }
 macro_rules! __ra_macro_fixture347 {($($var :  ident ($t :  ty )),+ )=>{$(impl  From <$t >  for  AttrOwner { fn  from ( t : $t )->  AttrOwner { AttrOwner ::$var ( t )}})+ }; }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
index 9bc1c54a3c6..b336f59ffee 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
@@ -40,6 +40,7 @@ pub struct StructData {
     pub repr: Option<ReprOptions>,
     pub visibility: RawVisibility,
     pub rustc_has_incoherent_inherent_impls: bool,
+    pub fundamental: bool,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -173,10 +174,10 @@ impl StructData {
         let item_tree = loc.id.item_tree(db);
         let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
         let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
-        let rustc_has_incoherent_inherent_impls = item_tree
-            .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into())
-            .by_key("rustc_has_incoherent_inherent_impls")
-            .exists();
+        let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
+        let rustc_has_incoherent_inherent_impls =
+            attrs.by_key("rustc_has_incoherent_inherent_impls").exists();
+        let fundamental = attrs.by_key("fundamental").exists();
 
         let strukt = &item_tree[loc.id.value];
         let (variant_data, diagnostics) = lower_fields(
@@ -196,6 +197,7 @@ impl StructData {
                 repr,
                 visibility: item_tree[strukt.visibility].clone(),
                 rustc_has_incoherent_inherent_impls,
+                fundamental,
             }),
             diagnostics.into(),
         )
@@ -215,10 +217,10 @@ impl StructData {
         let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
         let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
 
-        let rustc_has_incoherent_inherent_impls = item_tree
-            .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into())
-            .by_key("rustc_has_incoherent_inherent_impls")
-            .exists();
+        let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
+        let rustc_has_incoherent_inherent_impls =
+            attrs.by_key("rustc_has_incoherent_inherent_impls").exists();
+        let fundamental = attrs.by_key("fundamental").exists();
 
         let union = &item_tree[loc.id.value];
         let (variant_data, diagnostics) = lower_fields(
@@ -238,6 +240,7 @@ impl StructData {
                 repr,
                 visibility: item_tree[union.visibility].clone(),
                 rustc_has_incoherent_inherent_impls,
+                fundamental,
             }),
             diagnostics.into(),
         )
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index 3be477d4877..b70e658efd7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -24,7 +24,9 @@ use syntax::{ast, AstPtr, SyntaxNode, SyntaxNodePtr};
 use crate::{
     attr::Attrs,
     db::DefDatabase,
-    expr::{dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId},
+    expr::{
+        dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat,
+    },
     item_scope::BuiltinShadowMode,
     macro_id_to_def_id,
     nameres::DefMap,
@@ -432,6 +434,44 @@ impl Body {
         pats.shrink_to_fit();
         bindings.shrink_to_fit();
     }
+
+    pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
+        self.walk_pats(pat_id, &mut |pat| {
+            if let Pat::Bind { id, .. } = pat {
+                f(*id);
+            }
+        });
+    }
+
+    pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(&Pat)) {
+        let pat = &self[pat_id];
+        f(pat);
+        match pat {
+            Pat::Range { .. }
+            | Pat::Lit(..)
+            | Pat::Path(..)
+            | Pat::ConstBlock(..)
+            | Pat::Wild
+            | Pat::Missing => {}
+            &Pat::Bind { subpat, .. } => {
+                if let Some(subpat) = subpat {
+                    self.walk_pats(subpat, f);
+                }
+            }
+            Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
+                args.iter().copied().for_each(|p| self.walk_pats(p, f));
+            }
+            Pat::Ref { pat, .. } => self.walk_pats(*pat, f),
+            Pat::Slice { prefix, slice, suffix } => {
+                let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
+                total_iter.copied().for_each(|p| self.walk_pats(p, f));
+            }
+            Pat::Record { args, .. } => {
+                args.iter().for_each(|RecordFieldPat { pat, .. }| self.walk_pats(*pat, f));
+            }
+            Pat::Box { inner } => self.walk_pats(*inner, f),
+        }
+    }
 }
 
 impl Default for Body {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 83ce9b6acbb..fedaf395598 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -499,6 +499,8 @@ impl ExprCollector<'_> {
                         Movability::Movable
                     };
                     ClosureKind::Generator(movability)
+                } else if e.async_token().is_some() {
+                    ClosureKind::Async
                 } else {
                     ClosureKind::Closure
                 };
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index f8b159797e4..5a9b825a253 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -360,8 +360,14 @@ impl<'a> Printer<'a> {
                 w!(self, "]");
             }
             Expr::Closure { args, arg_types, ret_type, body, closure_kind } => {
-                if let ClosureKind::Generator(Movability::Static) = closure_kind {
-                    w!(self, "static ");
+                match closure_kind {
+                    ClosureKind::Generator(Movability::Static) => {
+                        w!(self, "static ");
+                    }
+                    ClosureKind::Async => {
+                        w!(self, "async ");
+                    }
+                    _ => (),
                 }
                 w!(self, "|");
                 for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index ee6e269fe55..1633a33bedd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -35,6 +35,7 @@ pub struct FunctionData {
     pub visibility: RawVisibility,
     pub abi: Option<Interned<str>>,
     pub legacy_const_generics_indices: Box<[u32]>,
+    pub rustc_allow_incoherent_impl: bool,
     flags: FnFlags,
 }
 
@@ -84,13 +85,14 @@ impl FunctionData {
             }
         }
 
-        let legacy_const_generics_indices = item_tree
-            .attrs(db, krate, ModItem::from(loc.id.value).into())
+        let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
+        let legacy_const_generics_indices = attrs
             .by_key("rustc_legacy_const_generics")
             .tt_values()
             .next()
             .map(parse_rustc_legacy_const_generics)
             .unwrap_or_default();
+        let rustc_allow_incoherent_impl = attrs.by_key("rustc_allow_incoherent_impl").exists();
 
         Arc::new(FunctionData {
             name: func.name.clone(),
@@ -108,6 +110,7 @@ impl FunctionData {
             abi: func.abi.clone(),
             legacy_const_generics_indices,
             flags,
+            rustc_allow_incoherent_impl,
         })
     }
 
@@ -171,6 +174,7 @@ pub struct TypeAliasData {
     pub visibility: RawVisibility,
     pub is_extern: bool,
     pub rustc_has_incoherent_inherent_impls: bool,
+    pub rustc_allow_incoherent_impl: bool,
     /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
     pub bounds: Vec<Interned<TypeBound>>,
 }
@@ -189,10 +193,14 @@ impl TypeAliasData {
             item_tree[typ.visibility].clone()
         };
 
-        let rustc_has_incoherent_inherent_impls = item_tree
-            .attrs(db, loc.container.module(db).krate(), ModItem::from(loc.id.value).into())
-            .by_key("rustc_has_incoherent_inherent_impls")
-            .exists();
+        let attrs = item_tree.attrs(
+            db,
+            loc.container.module(db).krate(),
+            ModItem::from(loc.id.value).into(),
+        );
+        let rustc_has_incoherent_inherent_impls =
+            attrs.by_key("rustc_has_incoherent_inherent_impls").exists();
+        let rustc_allow_incoherent_impl = attrs.by_key("rustc_allow_incoherent_impl").exists();
 
         Arc::new(TypeAliasData {
             name: typ.name.clone(),
@@ -200,6 +208,7 @@ impl TypeAliasData {
             visibility,
             is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
             rustc_has_incoherent_inherent_impls,
+            rustc_allow_incoherent_impl,
             bounds: typ.bounds.to_vec(),
         })
     }
@@ -212,11 +221,12 @@ pub struct TraitData {
     pub is_auto: bool,
     pub is_unsafe: bool,
     pub rustc_has_incoherent_inherent_impls: bool,
+    pub skip_array_during_method_dispatch: bool,
+    pub fundamental: bool,
     pub visibility: RawVisibility,
     /// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore
     /// method calls to this trait's methods when the receiver is an array and the crate edition is
     /// 2015 or 2018.
-    pub skip_array_during_method_dispatch: bool,
     // box it as the vec is usually empty anyways
     pub attribute_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
 }
@@ -245,6 +255,7 @@ impl TraitData {
             attrs.by_key("rustc_skip_array_during_method_dispatch").exists();
         let rustc_has_incoherent_inherent_impls =
             attrs.by_key("rustc_has_incoherent_inherent_impls").exists();
+        let fundamental = attrs.by_key("fundamental").exists();
         let mut collector =
             AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr));
         collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items);
@@ -260,6 +271,7 @@ impl TraitData {
                 visibility,
                 skip_array_during_method_dispatch,
                 rustc_has_incoherent_inherent_impls,
+                fundamental,
             }),
             diagnostics.into(),
         )
@@ -450,6 +462,7 @@ pub struct ConstData {
     pub name: Option<Name>,
     pub type_ref: Interned<TypeRef>,
     pub visibility: RawVisibility,
+    pub rustc_allow_incoherent_impl: bool,
 }
 
 impl ConstData {
@@ -463,10 +476,16 @@ impl ConstData {
             item_tree[konst.visibility].clone()
         };
 
+        let rustc_allow_incoherent_impl = item_tree
+            .attrs(db, loc.container.module(db).krate(), ModItem::from(loc.id.value).into())
+            .by_key("rustc_allow_incoherent_impl")
+            .exists();
+
         Arc::new(ConstData {
             name: konst.name.clone(),
             type_ref: konst.type_ref.clone(),
             visibility,
+            rustc_allow_incoherent_impl,
         })
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index 270cfa06e58..9371fc14dd8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -3,7 +3,7 @@ use std::sync::Arc;
 
 use base_db::{salsa, CrateId, SourceDatabase, Upcast};
 use either::Either;
-use hir_expand::{db::AstDatabase, HirFileId};
+use hir_expand::{db::ExpandDatabase, HirFileId};
 use intern::Interned;
 use la_arena::ArenaMap;
 use syntax::{ast, AstPtr};
@@ -64,7 +64,7 @@ pub trait InternDatabase: SourceDatabase {
 }
 
 #[salsa::query_group(DefDatabaseStorage)]
-pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
+pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDatabase> {
     #[salsa::input]
     fn enable_proc_attr_macros(&self) -> bool;
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
index bbea608c55e..19fa6b25419 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
@@ -245,6 +245,7 @@ pub enum Expr {
 pub enum ClosureKind {
     Closure,
     Generator(Movability),
+    Async,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs
index 5ab90d92d9b..314bf22b95e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs
@@ -20,7 +20,7 @@ use ::mbe::TokenMap;
 use base_db::{fixture::WithFixture, ProcMacro, SourceDatabase};
 use expect_test::Expect;
 use hir_expand::{
-    db::{AstDatabase, TokenExpander},
+    db::{ExpandDatabase, TokenExpander},
     AstId, InFile, MacroDefId, MacroDefKind, MacroFile,
 };
 use stdx::format_to;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index 7d7240e7e8c..4efe8c58a69 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -120,6 +120,8 @@ pub struct DefMap {
     registered_tools: Vec<SmolStr>,
     /// Unstable features of Rust enabled with `#![feature(A, B)]`.
     unstable_features: FxHashSet<SmolStr>,
+    /// #[rustc_coherence_is_core]
+    rustc_coherence_is_core: bool,
 
     edition: Edition,
     recursion_limit: Option<u32>,
@@ -215,7 +217,7 @@ pub struct ModuleData {
     pub origin: ModuleOrigin,
     /// Declared visibility of this module.
     pub visibility: Visibility,
-
+    /// Always [`None`] for block modules
     pub parent: Option<LocalModuleId>,
     pub children: FxHashMap<Name, LocalModuleId>,
     pub scope: ItemScope,
@@ -292,6 +294,7 @@ impl DefMap {
             registered_tools: Vec::new(),
             unstable_features: FxHashSet::default(),
             diagnostics: Vec::new(),
+            rustc_coherence_is_core: false,
         }
     }
 
@@ -325,6 +328,10 @@ impl DefMap {
         self.unstable_features.contains(feature)
     }
 
+    pub fn is_rustc_coherence_is_core(&self) -> bool {
+        self.rustc_coherence_is_core
+    }
+
     pub fn root(&self) -> LocalModuleId {
         self.root
     }
@@ -337,7 +344,7 @@ impl DefMap {
         self.proc_macro_loading_error.as_deref()
     }
 
-    pub(crate) fn krate(&self) -> CrateId {
+    pub fn krate(&self) -> CrateId {
         self.krate
     }
 
@@ -425,7 +432,7 @@ impl DefMap {
         Some(self.block?.parent)
     }
 
-    /// Returns the module containing `local_mod`, either the parent `mod`, or the module containing
+    /// Returns the module containing `local_mod`, either the parent `mod`, or the module (or block) containing
     /// the block, if `self` corresponds to a block expression.
     pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
         match self[local_mod].parent {
@@ -498,6 +505,7 @@ impl DefMap {
             krate: _,
             prelude: _,
             root: _,
+            rustc_coherence_is_core: _,
         } = self;
 
         extern_prelude.shrink_to_fit();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 70acc3442c3..ddcee77ec4c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -87,10 +87,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
                     // FIXME: a hacky way to create a Name from string.
                     let name =
                         tt::Ident { text: it.name.clone(), span: tt::TokenId::unspecified() };
-                    (
-                        name.as_name(),
-                        ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)),
-                    )
+                    (name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32)))
                 })
                 .collect()
         }
@@ -299,6 +296,11 @@ impl DefCollector<'_> {
                     continue;
                 }
 
+                if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") {
+                    self.def_map.rustc_coherence_is_core = true;
+                    continue;
+                }
+
                 if *attr_name == hir_expand::name![feature] {
                     let features =
                         attr.parse_path_comma_token_tree().into_iter().flatten().filter_map(
@@ -581,7 +583,7 @@ impl DefCollector<'_> {
         let kind = def.kind.to_basedb_kind();
         let (expander, kind) = match self.proc_macros.iter().find(|(n, _)| n == &def.name) {
             Some(&(_, expander)) => (expander, kind),
-            None => (ProcMacroExpander::dummy(self.def_map.krate), kind),
+            None => (ProcMacroExpander::dummy(), kind),
         };
 
         let proc_macro_id =
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
index b7908bddaa1..ee143b19ae5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
@@ -9,7 +9,7 @@ use base_db::{
     salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition,
     SourceDatabase, Upcast,
 };
-use hir_expand::{db::AstDatabase, InFile};
+use hir_expand::{db::ExpandDatabase, InFile};
 use stdx::hash::NoHashHashSet;
 use syntax::{algo, ast, AstNode};
 
@@ -23,7 +23,7 @@ use crate::{
 #[salsa::database(
     base_db::SourceDatabaseExtStorage,
     base_db::SourceDatabaseStorage,
-    hir_expand::db::AstDatabaseStorage,
+    hir_expand::db::ExpandDatabaseStorage,
     crate::db::InternDatabaseStorage,
     crate::db::DefDatabaseStorage
 )]
@@ -40,8 +40,8 @@ impl Default for TestDB {
     }
 }
 
-impl Upcast<dyn AstDatabase> for TestDB {
-    fn upcast(&self) -> &(dyn AstDatabase + 'static) {
+impl Upcast<dyn ExpandDatabase> for TestDB {
+    fn upcast(&self) -> &(dyn ExpandDatabase + 'static) {
         &*self
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
index c9fcaae56cf..ab76ed43d3a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
@@ -131,21 +131,23 @@ impl Visibility {
         // visibility as the containing module (even though no items are directly nameable from
         // there, getting this right is important for method resolution).
         // In that case, we adjust the visibility of `to_module` to point to the containing module.
+
         // Additional complication: `to_module` might be in `from_module`'s `DefMap`, which we're
         // currently computing, so we must not call the `def_map` query for it.
-        let arc;
-        let to_module_def_map =
-            if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() {
-                cov_mark::hit!(is_visible_from_same_block_def_map);
-                def_map
-            } else {
-                arc = to_module.def_map(db);
-                &arc
-            };
-        let is_block_root =
-            to_module.block.is_some() && to_module_def_map[to_module.local_id].parent.is_none();
-        if is_block_root {
-            to_module = to_module_def_map.containing_module(to_module.local_id).unwrap();
+        let mut arc;
+        loop {
+            let to_module_def_map =
+                if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() {
+                    cov_mark::hit!(is_visible_from_same_block_def_map);
+                    def_map
+                } else {
+                    arc = to_module.def_map(db);
+                    &arc
+                };
+            match to_module_def_map.parent() {
+                Some(parent) => to_module = parent,
+                None => break,
+            }
         }
 
         // from_module needs to be a descendant of to_module
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index 5c04f8e8b8f..8d1e88725ec 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -10,7 +10,7 @@ use smallvec::{smallvec, SmallVec};
 use syntax::{ast, match_ast, AstNode, SmolStr, SyntaxNode};
 
 use crate::{
-    db::AstDatabase,
+    db::ExpandDatabase,
     hygiene::Hygiene,
     mod_path::{ModPath, PathKind},
     name::AsName,
@@ -38,7 +38,7 @@ impl ops::Deref for RawAttrs {
 impl RawAttrs {
     pub const EMPTY: Self = Self { entries: None };
 
-    pub fn new(db: &dyn AstDatabase, owner: &dyn ast::HasAttrs, hygiene: &Hygiene) -> Self {
+    pub fn new(db: &dyn ExpandDatabase, owner: &dyn ast::HasAttrs, hygiene: &Hygiene) -> Self {
         let entries = collect_attrs(owner)
             .filter_map(|(id, attr)| match attr {
                 Either::Left(attr) => {
@@ -55,7 +55,7 @@ impl RawAttrs {
         Self { entries: if entries.is_empty() { None } else { Some(entries) } }
     }
 
-    pub fn from_attrs_owner(db: &dyn AstDatabase, owner: InFile<&dyn ast::HasAttrs>) -> Self {
+    pub fn from_attrs_owner(db: &dyn ExpandDatabase, owner: InFile<&dyn ast::HasAttrs>) -> Self {
         let hygiene = Hygiene::new(db, owner.file_id);
         Self::new(db, owner.value, &hygiene)
     }
@@ -87,7 +87,7 @@ impl RawAttrs {
 
     /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`.
     // FIXME: This should return a different type
-    pub fn filter(self, db: &dyn AstDatabase, krate: CrateId) -> RawAttrs {
+    pub fn filter(self, db: &dyn ExpandDatabase, krate: CrateId) -> RawAttrs {
         let has_cfg_attrs = self
             .iter()
             .any(|attr| attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr]));
@@ -199,7 +199,7 @@ impl fmt::Display for AttrInput {
 
 impl Attr {
     fn from_src(
-        db: &dyn AstDatabase,
+        db: &dyn ExpandDatabase,
         ast: ast::Meta,
         hygiene: &Hygiene,
         id: AttrId,
@@ -221,7 +221,7 @@ impl Attr {
     }
 
     fn from_tt(
-        db: &dyn AstDatabase,
+        db: &dyn ExpandDatabase,
         tt: &tt::Subtree,
         hygiene: &Hygiene,
         id: AttrId,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs
index 906ca991d73..277ecd93994 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs
@@ -1,6 +1,6 @@
 //! Builtin attributes.
 
-use crate::{db::AstDatabase, name, tt, ExpandResult, MacroCallId, MacroCallKind};
+use crate::{db::ExpandDatabase, name, tt, ExpandResult, MacroCallId, MacroCallKind};
 
 macro_rules! register_builtin {
     ( $(($name:ident, $variant:ident) => $expand:ident),* ) => {
@@ -12,7 +12,7 @@ macro_rules! register_builtin {
         impl BuiltinAttrExpander {
             pub fn expand(
                 &self,
-                db: &dyn AstDatabase,
+                db: &dyn ExpandDatabase,
                 id: MacroCallId,
                 tt: &tt::Subtree,
             ) -> ExpandResult<tt::Subtree> {
@@ -60,7 +60,7 @@ pub fn find_builtin_attr(ident: &name::Name) -> Option<BuiltinAttrExpander> {
 }
 
 fn dummy_attr_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -90,7 +90,7 @@ fn dummy_attr_expand(
 /// So this hacky approach is a lot more friendly for us, though it does require a bit of support in
 /// [`hir::Semantics`] to make this work.
 fn derive_attr_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
index 060a680542f..5c1a75132ee 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
@@ -9,7 +9,7 @@ use syntax::{
     match_ast,
 };
 
-use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId};
+use crate::{db::ExpandDatabase, name, quote, ExpandError, ExpandResult, MacroCallId};
 
 macro_rules! register_builtin {
     ( $($trait:ident => $expand:ident),* ) => {
@@ -21,7 +21,7 @@ macro_rules! register_builtin {
         impl BuiltinDeriveExpander {
             pub fn expand(
                 &self,
-                db: &dyn AstDatabase,
+                db: &dyn ExpandDatabase,
                 id: MacroCallId,
                 tt: &tt::Subtree,
             ) -> ExpandResult<tt::Subtree> {
@@ -141,7 +141,7 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu
     ExpandResult::ok(expanded)
 }
 
-fn find_builtin_crate(db: &dyn AstDatabase, id: MacroCallId) -> tt::TokenTree {
+fn find_builtin_crate(db: &dyn ExpandDatabase, id: MacroCallId) -> tt::TokenTree {
     // FIXME: make hygiene works for builtin derive macro
     // such that $crate can be used here.
     let cg = db.crate_graph();
@@ -158,7 +158,7 @@ fn find_builtin_crate(db: &dyn AstDatabase, id: MacroCallId) -> tt::TokenTree {
 }
 
 fn copy_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -167,7 +167,7 @@ fn copy_expand(
 }
 
 fn clone_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -176,7 +176,7 @@ fn clone_expand(
 }
 
 fn default_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -185,7 +185,7 @@ fn default_expand(
 }
 
 fn debug_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -194,7 +194,7 @@ fn debug_expand(
 }
 
 fn hash_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -202,13 +202,17 @@ fn hash_expand(
     expand_simple_derive(tt, quote! { #krate::hash::Hash })
 }
 
-fn eq_expand(db: &dyn AstDatabase, id: MacroCallId, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> {
+fn eq_expand(
+    db: &dyn ExpandDatabase,
+    id: MacroCallId,
+    tt: &tt::Subtree,
+) -> ExpandResult<tt::Subtree> {
     let krate = find_builtin_crate(db, id);
     expand_simple_derive(tt, quote! { #krate::cmp::Eq })
 }
 
 fn partial_eq_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -217,7 +221,7 @@ fn partial_eq_expand(
 }
 
 fn ord_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -226,7 +230,7 @@ fn ord_expand(
 }
 
 fn partial_ord_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
index 295083a37f2..44510f2b7ff 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
@@ -10,7 +10,7 @@ use syntax::{
 };
 
 use crate::{
-    db::AstDatabase, name, quote, tt, ExpandError, ExpandResult, MacroCallId, MacroCallLoc,
+    db::ExpandDatabase, name, quote, tt, ExpandError, ExpandResult, MacroCallId, MacroCallLoc,
 };
 
 macro_rules! register_builtin {
@@ -28,7 +28,7 @@ macro_rules! register_builtin {
         impl BuiltinFnLikeExpander {
             pub fn expand(
                 &self,
-                db: &dyn AstDatabase,
+                db: &dyn ExpandDatabase,
                 id: MacroCallId,
                 tt: &tt::Subtree,
             ) -> ExpandResult<tt::Subtree> {
@@ -42,7 +42,7 @@ macro_rules! register_builtin {
         impl EagerExpander {
             pub fn expand(
                 &self,
-                db: &dyn AstDatabase,
+                db: &dyn ExpandDatabase,
                 arg_id: MacroCallId,
                 tt: &tt::Subtree,
             ) -> ExpandResult<ExpandedEager> {
@@ -121,7 +121,7 @@ const DOLLAR_CRATE: tt::Ident =
     tt::Ident { text: SmolStr::new_inline("$crate"), span: tt::TokenId::unspecified() };
 
 fn module_path_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     _tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -130,7 +130,7 @@ fn module_path_expand(
 }
 
 fn line_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     _tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -144,7 +144,7 @@ fn line_expand(
 }
 
 fn log_syntax_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     _tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -152,7 +152,7 @@ fn log_syntax_expand(
 }
 
 fn trace_macros_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     _tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -160,7 +160,7 @@ fn trace_macros_expand(
 }
 
 fn stringify_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -174,7 +174,7 @@ fn stringify_expand(
 }
 
 fn column_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     _tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -188,7 +188,7 @@ fn column_expand(
 }
 
 fn assert_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -218,7 +218,7 @@ fn assert_expand(
 }
 
 fn file_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     _tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -234,7 +234,7 @@ fn file_expand(
 }
 
 fn format_args_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -276,7 +276,7 @@ fn format_args_expand(
 }
 
 fn asm_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -304,7 +304,7 @@ fn asm_expand(
 }
 
 fn global_asm_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     _tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -313,7 +313,7 @@ fn global_asm_expand(
 }
 
 fn cfg_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -325,7 +325,7 @@ fn cfg_expand(
 }
 
 fn panic_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -343,7 +343,7 @@ fn panic_expand(
 }
 
 fn unreachable_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
@@ -379,7 +379,7 @@ fn unquote_byte_string(lit: &tt::Literal) -> Option<Vec<u8>> {
 }
 
 fn compile_error_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<ExpandedEager> {
@@ -395,7 +395,7 @@ fn compile_error_expand(
 }
 
 fn concat_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _arg_id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<ExpandedEager> {
@@ -441,7 +441,7 @@ fn concat_expand(
 }
 
 fn concat_bytes_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _arg_id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<ExpandedEager> {
@@ -507,7 +507,7 @@ fn concat_bytes_expand_subtree(
 }
 
 fn concat_idents_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _arg_id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<ExpandedEager> {
@@ -529,7 +529,7 @@ fn concat_idents_expand(
 }
 
 fn relative_file(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     call_id: MacroCallId,
     path_str: &str,
     allow_recursion: bool,
@@ -558,7 +558,7 @@ fn parse_string(tt: &tt::Subtree) -> Result<String, ExpandError> {
 }
 
 fn include_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     arg_id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<ExpandedEager> {
@@ -583,7 +583,7 @@ fn include_expand(
 }
 
 fn include_bytes_expand(
-    _db: &dyn AstDatabase,
+    _db: &dyn ExpandDatabase,
     _arg_id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<ExpandedEager> {
@@ -606,7 +606,7 @@ fn include_bytes_expand(
 }
 
 fn include_str_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     arg_id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<ExpandedEager> {
@@ -637,13 +637,13 @@ fn include_str_expand(
     ExpandResult::ok(ExpandedEager::new(quote!(#text)))
 }
 
-fn get_env_inner(db: &dyn AstDatabase, arg_id: MacroCallId, key: &str) -> Option<String> {
+fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &str) -> Option<String> {
     let krate = db.lookup_intern_macro_call(arg_id).krate;
     db.crate_graph()[krate].env.get(key)
 }
 
 fn env_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     arg_id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<ExpandedEager> {
@@ -679,7 +679,7 @@ fn env_expand(
 }
 
 fn option_env_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     arg_id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<ExpandedEager> {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index 76016274f0e..45572499e84 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -44,7 +44,7 @@ pub enum TokenExpander {
 impl TokenExpander {
     fn expand(
         &self,
-        db: &dyn AstDatabase,
+        db: &dyn ExpandDatabase,
         id: MacroCallId,
         tt: &tt::Subtree,
     ) -> ExpandResult<tt::Subtree> {
@@ -83,9 +83,8 @@ impl TokenExpander {
     }
 }
 
-// FIXME: rename to ExpandDatabase
-#[salsa::query_group(AstDatabaseStorage)]
-pub trait AstDatabase: SourceDatabase {
+#[salsa::query_group(ExpandDatabaseStorage)]
+pub trait ExpandDatabase: SourceDatabase {
     fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
 
     /// Main public API -- parses a hir file, not caring whether it's a real
@@ -138,7 +137,7 @@ pub trait AstDatabase: SourceDatabase {
 /// token. The `token_to_map` mapped down into the expansion, with the mapped
 /// token returned.
 pub fn expand_speculative(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     actual_macro_call: MacroCallId,
     speculative_args: &SyntaxNode,
     token_to_map: SyntaxToken,
@@ -211,7 +210,7 @@ pub fn expand_speculative(
     let mut speculative_expansion = match loc.def.kind {
         MacroDefKind::ProcMacro(expander, ..) => {
             tt.delimiter = tt::Delimiter::unspecified();
-            expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
+            expander.expand(db, loc.def.krate, loc.krate, &tt, attr_arg.as_ref())
         }
         MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
             pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?)
@@ -236,12 +235,12 @@ pub fn expand_speculative(
     Some((node.syntax_node(), token))
 }
 
-fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
+fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
     let map = db.parse_or_expand(file_id).map(|it| AstIdMap::from_source(&it)).unwrap_or_default();
     Arc::new(map)
 }
 
-fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
+fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
     match file_id.repr() {
         HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
         HirFileIdRepr::MacroFile(macro_file) => {
@@ -253,13 +252,13 @@ fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNod
 }
 
 fn parse_macro_expansion(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     macro_file: MacroFile,
 ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> {
     let _p = profile::span("parse_macro_expansion");
-    let result = db.macro_expand(macro_file.macro_call_id);
+    let mbe::ValueResult { value, err } = db.macro_expand(macro_file.macro_call_id);
 
-    if let Some(err) = &result.err {
+    if let Some(err) = &err {
         // Note:
         // The final goal we would like to make all parse_macro success,
         // such that the following log will not call anyway.
@@ -280,9 +279,9 @@ fn parse_macro_expansion(
             parents
         );
     }
-    let tt = match result.value {
+    let tt = match value {
         Some(tt) => tt,
-        None => return ExpandResult { value: None, err: result.err },
+        None => return ExpandResult { value: None, err },
     };
 
     let expand_to = macro_expand_to(db, macro_file.macro_call_id);
@@ -292,11 +291,11 @@ fn parse_macro_expansion(
 
     let (parse, rev_token_map) = token_tree_to_syntax_node(&tt, expand_to);
 
-    ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: result.err }
+    ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err }
 }
 
 fn macro_arg(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     id: MacroCallId,
 ) -> Option<Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>> {
     let arg = db.macro_arg_text(id)?;
@@ -357,7 +356,7 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet<Sy
     .unwrap_or_default()
 }
 
-fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
+fn macro_arg_text(db: &dyn ExpandDatabase, id: MacroCallId) -> Option<GreenNode> {
     let loc = db.lookup_intern_macro_call(id);
     let arg = loc.kind.arg(db)?;
     if matches!(loc.kind, MacroCallKind::FnLike { .. }) {
@@ -380,7 +379,10 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
     Some(arg.green().into())
 }
 
-fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Result<Arc<TokenExpander>, mbe::ParseError> {
+fn macro_def(
+    db: &dyn ExpandDatabase,
+    id: MacroDefId,
+) -> Result<Arc<TokenExpander>, mbe::ParseError> {
     match id.kind {
         MacroDefKind::Declarative(ast_id) => {
             let (mac, def_site_token_map) = match ast_id.to_node(db) {
@@ -419,7 +421,10 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Result<Arc<TokenExpander>,
     }
 }
 
-fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>> {
+fn macro_expand(
+    db: &dyn ExpandDatabase,
+    id: MacroCallId,
+) -> ExpandResult<Option<Arc<tt::Subtree>>> {
     let _p = profile::span("macro_expand");
     let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
     if let Some(eager) = &loc.eager {
@@ -469,11 +474,11 @@ fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Ar
     ExpandResult { value: Some(Arc::new(tt)), err }
 }
 
-fn macro_expand_error(db: &dyn AstDatabase, macro_call: MacroCallId) -> Option<ExpandError> {
+fn macro_expand_error(db: &dyn ExpandDatabase, macro_call: MacroCallId) -> Option<ExpandError> {
     db.macro_expand(macro_call).err
 }
 
-fn expand_proc_macro(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<tt::Subtree> {
+fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<tt::Subtree> {
     let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
     let macro_arg = match db.macro_arg(id) {
         Some(it) => it,
@@ -499,14 +504,14 @@ fn expand_proc_macro(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<tt::
         _ => None,
     };
 
-    expander.expand(db, loc.krate, &macro_arg.0, attr_arg.as_ref())
+    expander.expand(db, loc.def.krate, loc.krate, &macro_arg.0, attr_arg.as_ref())
 }
 
-fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> {
+fn hygiene_frame(db: &dyn ExpandDatabase, file_id: HirFileId) -> Arc<HygieneFrame> {
     Arc::new(HygieneFrame::new(db, file_id))
 }
 
-fn macro_expand_to(db: &dyn AstDatabase, id: MacroCallId) -> ExpandTo {
+fn macro_expand_to(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandTo {
     let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
     loc.kind.expand_to()
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
index dfab7ec92c7..aca41b11f92 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
@@ -25,7 +25,7 @@ use syntax::{ted, SyntaxNode};
 
 use crate::{
     ast::{self, AstNode},
-    db::AstDatabase,
+    db::ExpandDatabase,
     hygiene::Hygiene,
     mod_path::ModPath,
     EagerCallInfo, ExpandError, ExpandResult, ExpandTo, InFile, MacroCallId, MacroCallKind,
@@ -96,7 +96,7 @@ impl ErrorSink for &'_ mut dyn FnMut(ExpandError) {
 }
 
 pub fn expand_eager_macro(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     krate: CrateId,
     macro_call: InFile<ast::MacroCall>,
     def: MacroDefId,
@@ -172,7 +172,7 @@ fn to_subtree(node: &SyntaxNode) -> crate::tt::Subtree {
 }
 
 fn lazy_expand(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     def: &MacroDefId,
     macro_call: InFile<ast::MacroCall>,
     krate: CrateId,
@@ -193,7 +193,7 @@ fn lazy_expand(
 }
 
 fn eager_macro_recur(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     hygiene: &Hygiene,
     curr: InFile<SyntaxNode>,
     krate: CrateId,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
index c811d1c66a8..b273f21768c 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
@@ -636,9 +636,8 @@ fn foo() {
     if {}
 }
 "#,
-            // the {} gets parsed as the condition, I think?
             expect![[r#"
-fn foo () {if {} {}}
+fn foo () {if __ra_fixup {} {}}
 "#]],
         )
     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
index 2300ee9d089..2eb56fc9e8b 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
@@ -14,7 +14,7 @@ use syntax::{
 };
 
 use crate::{
-    db::{self, AstDatabase},
+    db::{self, ExpandDatabase},
     fixup,
     name::{AsName, Name},
     HirFileId, InFile, MacroCallKind, MacroCallLoc, MacroDefKind, MacroFile,
@@ -26,7 +26,7 @@ pub struct Hygiene {
 }
 
 impl Hygiene {
-    pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene {
+    pub fn new(db: &dyn ExpandDatabase, file_id: HirFileId) -> Hygiene {
         Hygiene { frames: Some(HygieneFrames::new(db, file_id)) }
     }
 
@@ -37,7 +37,7 @@ impl Hygiene {
     // FIXME: this should just return name
     pub fn name_ref_to_name(
         &self,
-        db: &dyn AstDatabase,
+        db: &dyn ExpandDatabase,
         name_ref: ast::NameRef,
     ) -> Either<Name, CrateId> {
         if let Some(frames) = &self.frames {
@@ -51,7 +51,7 @@ impl Hygiene {
         Either::Left(name_ref.as_name())
     }
 
-    pub fn local_inner_macros(&self, db: &dyn AstDatabase, path: ast::Path) -> Option<CrateId> {
+    pub fn local_inner_macros(&self, db: &dyn ExpandDatabase, path: ast::Path) -> Option<CrateId> {
         let mut token = path.syntax().first_token()?.text_range();
         let frames = self.frames.as_ref()?;
         let mut current = &frames.0;
@@ -87,13 +87,13 @@ pub struct HygieneFrame {
 }
 
 impl HygieneFrames {
-    fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self {
+    fn new(db: &dyn ExpandDatabase, file_id: HirFileId) -> Self {
         // Note that this intentionally avoids the `hygiene_frame` query to avoid blowing up memory
         // usage. The query is only helpful for nested `HygieneFrame`s as it avoids redundant work.
         HygieneFrames(Arc::new(HygieneFrame::new(db, file_id)))
     }
 
-    fn root_crate(&self, db: &dyn AstDatabase, node: &SyntaxNode) -> Option<CrateId> {
+    fn root_crate(&self, db: &dyn ExpandDatabase, node: &SyntaxNode) -> Option<CrateId> {
         let mut token = node.first_token()?.text_range();
         let mut result = self.0.krate;
         let mut current = self.0.clone();
@@ -136,7 +136,7 @@ struct HygieneInfo {
 impl HygieneInfo {
     fn map_ident_up(
         &self,
-        db: &dyn AstDatabase,
+        db: &dyn ExpandDatabase,
         token: TextRange,
     ) -> Option<(InFile<TextRange>, Origin)> {
         let token_id = self.exp_map.token_by_range(token)?;
@@ -175,7 +175,7 @@ impl HygieneInfo {
 }
 
 fn make_hygiene_info(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     macro_file: MacroFile,
     loc: &MacroCallLoc,
 ) -> Option<HygieneInfo> {
@@ -215,7 +215,7 @@ fn make_hygiene_info(
 }
 
 impl HygieneFrame {
-    pub(crate) fn new(db: &dyn AstDatabase, file_id: HirFileId) -> HygieneFrame {
+    pub(crate) fn new(db: &dyn ExpandDatabase, file_id: HirFileId) -> HygieneFrame {
         let (info, krate, local_inner) = match file_id.macro_file() {
             None => (None, None, false),
             Some(macro_file) => {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index 39fc08ecdcf..5e99eacc1b6 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -198,7 +198,7 @@ impl HirFileId {
 
     /// For macro-expansion files, returns the file original source file the
     /// expansion originated from.
-    pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId {
+    pub fn original_file(self, db: &dyn db::ExpandDatabase) -> FileId {
         let mut file_id = self;
         loop {
             match file_id.repr() {
@@ -214,7 +214,7 @@ impl HirFileId {
         }
     }
 
-    pub fn expansion_level(self, db: &dyn db::AstDatabase) -> u32 {
+    pub fn expansion_level(self, db: &dyn db::ExpandDatabase) -> u32 {
         let mut level = 0;
         let mut curr = self;
         while let Some(macro_file) = curr.macro_file() {
@@ -227,14 +227,14 @@ impl HirFileId {
     }
 
     /// If this is a macro call, returns the syntax node of the call.
-    pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
+    pub fn call_node(self, db: &dyn db::ExpandDatabase) -> Option<InFile<SyntaxNode>> {
         let macro_file = self.macro_file()?;
         let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
         Some(loc.kind.to_node(db))
     }
 
     /// If this is a macro call, returns the syntax node of the very first macro call this file resides in.
-    pub fn original_call_node(self, db: &dyn db::AstDatabase) -> Option<(FileId, SyntaxNode)> {
+    pub fn original_call_node(self, db: &dyn db::ExpandDatabase) -> Option<(FileId, SyntaxNode)> {
         let mut call =
             db.lookup_intern_macro_call(self.macro_file()?.macro_call_id).kind.to_node(db);
         loop {
@@ -248,7 +248,7 @@ impl HirFileId {
     }
 
     /// Return expansion information if it is a macro-expansion file
-    pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> {
+    pub fn expansion_info(self, db: &dyn db::ExpandDatabase) -> Option<ExpansionInfo> {
         let macro_file = self.macro_file()?;
         let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 
@@ -294,7 +294,7 @@ impl HirFileId {
     }
 
     /// Indicate it is macro file generated for builtin derive
-    pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option<InFile<ast::Attr>> {
+    pub fn is_builtin_derive(&self, db: &dyn db::ExpandDatabase) -> Option<InFile<ast::Attr>> {
         let macro_file = self.macro_file()?;
         let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
         let attr = match loc.def.kind {
@@ -304,7 +304,7 @@ impl HirFileId {
         Some(attr.with_value(ast::Attr::cast(attr.value.clone())?))
     }
 
-    pub fn is_custom_derive(&self, db: &dyn db::AstDatabase) -> bool {
+    pub fn is_custom_derive(&self, db: &dyn db::ExpandDatabase) -> bool {
         match self.macro_file() {
             Some(macro_file) => {
                 let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
@@ -315,7 +315,7 @@ impl HirFileId {
     }
 
     /// Return whether this file is an include macro
-    pub fn is_include_macro(&self, db: &dyn db::AstDatabase) -> bool {
+    pub fn is_include_macro(&self, db: &dyn db::ExpandDatabase) -> bool {
         match self.macro_file() {
             Some(macro_file) => {
                 let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
@@ -326,7 +326,7 @@ impl HirFileId {
     }
 
     /// Return whether this file is an attr macro
-    pub fn is_attr_macro(&self, db: &dyn db::AstDatabase) -> bool {
+    pub fn is_attr_macro(&self, db: &dyn db::ExpandDatabase) -> bool {
         match self.macro_file() {
             Some(macro_file) => {
                 let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
@@ -338,7 +338,7 @@ impl HirFileId {
 
     /// Return whether this file is the pseudo expansion of the derive attribute.
     /// See [`crate::builtin_attr_macro::derive_attr_expand`].
-    pub fn is_derive_attr_pseudo_expansion(&self, db: &dyn db::AstDatabase) -> bool {
+    pub fn is_derive_attr_pseudo_expansion(&self, db: &dyn db::ExpandDatabase) -> bool {
         match self.macro_file() {
             Some(macro_file) => {
                 let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
@@ -384,7 +384,7 @@ impl HirFileId {
 impl MacroDefId {
     pub fn as_lazy_macro(
         self,
-        db: &dyn db::AstDatabase,
+        db: &dyn db::ExpandDatabase,
         krate: CrateId,
         kind: MacroCallKind,
     ) -> MacroCallId {
@@ -427,7 +427,7 @@ impl MacroCallKind {
         }
     }
 
-    pub fn to_node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
+    pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> InFile<SyntaxNode> {
         match self {
             MacroCallKind::FnLike { ast_id, .. } => {
                 ast_id.with_value(ast_id.to_node(db).syntax().clone())
@@ -465,7 +465,7 @@ impl MacroCallKind {
     /// Returns the original file range that best describes the location of this macro call.
     ///
     /// Unlike `MacroCallKind::original_call_range`, this also spans the item of attributes and derives.
-    pub fn original_call_range_with_body(self, db: &dyn db::AstDatabase) -> FileRange {
+    pub fn original_call_range_with_body(self, db: &dyn db::ExpandDatabase) -> FileRange {
         let mut kind = self;
         let file_id = loop {
             match kind.file_id().repr() {
@@ -490,7 +490,7 @@ impl MacroCallKind {
     /// Here we try to roughly match what rustc does to improve diagnostics: fn-like macros
     /// get the whole `ast::MacroCall`, attribute macros get the attribute's range, and derives
     /// get only the specific derive that is being referred to.
-    pub fn original_call_range(self, db: &dyn db::AstDatabase) -> FileRange {
+    pub fn original_call_range(self, db: &dyn db::ExpandDatabase) -> FileRange {
         let mut kind = self;
         let file_id = loop {
             match kind.file_id().repr() {
@@ -529,7 +529,7 @@ impl MacroCallKind {
         FileRange { range, file_id }
     }
 
-    fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
+    fn arg(&self, db: &dyn db::ExpandDatabase) -> Option<SyntaxNode> {
         match self {
             MacroCallKind::FnLike { ast_id, .. } => {
                 Some(ast_id.to_node(db).token_tree()?.syntax().clone())
@@ -597,7 +597,7 @@ impl ExpansionInfo {
     ///     Both of these only have one simple call site input so no special handling is required here.
     pub fn map_token_down(
         &self,
-        db: &dyn db::AstDatabase,
+        db: &dyn db::ExpandDatabase,
         item: Option<ast::Item>,
         token: InFile<&SyntaxToken>,
     ) -> Option<impl Iterator<Item = InFile<SyntaxToken>> + '_> {
@@ -666,7 +666,7 @@ impl ExpansionInfo {
     /// Map a token up out of the expansion it resides in into the arguments of the macro call of the expansion.
     pub fn map_token_up(
         &self,
-        db: &dyn db::AstDatabase,
+        db: &dyn db::ExpandDatabase,
         token: InFile<&SyntaxToken>,
     ) -> Option<(InFile<SyntaxToken>, Origin)> {
         // Fetch the id through its text range,
@@ -717,7 +717,7 @@ impl ExpansionInfo {
 pub type AstId<N> = InFile<FileAstId<N>>;
 
 impl<N: AstNode> AstId<N> {
-    pub fn to_node(&self, db: &dyn db::AstDatabase) -> N {
+    pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> N {
         let root = db.parse_or_expand(self.file_id).unwrap();
         db.ast_id_map(self.file_id).get(self.value).to_node(&root)
     }
@@ -753,7 +753,7 @@ impl<T> InFile<T> {
         self.with_value(&self.value)
     }
 
-    pub fn file_syntax(&self, db: &dyn db::AstDatabase) -> SyntaxNode {
+    pub fn file_syntax(&self, db: &dyn db::ExpandDatabase) -> SyntaxNode {
         db.parse_or_expand(self.file_id).expect("source created from invalid file")
     }
 }
@@ -783,7 +783,7 @@ impl<L, R> InFile<Either<L, R>> {
 impl<'a> InFile<&'a SyntaxNode> {
     pub fn ancestors_with_macros(
         self,
-        db: &dyn db::AstDatabase,
+        db: &dyn db::ExpandDatabase,
     ) -> impl Iterator<Item = InFile<SyntaxNode>> + Clone + '_ {
         iter::successors(Some(self.cloned()), move |node| match node.value.parent() {
             Some(parent) => Some(node.with_value(parent)),
@@ -794,7 +794,7 @@ impl<'a> InFile<&'a SyntaxNode> {
     /// Skips the attributed item that caused the macro invocation we are climbing up
     pub fn ancestors_with_macros_skip_attr_item(
         self,
-        db: &dyn db::AstDatabase,
+        db: &dyn db::ExpandDatabase,
     ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
         let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() {
             Some(parent) => Some(node.with_value(parent)),
@@ -816,7 +816,7 @@ impl<'a> InFile<&'a SyntaxNode> {
     ///
     /// For attributes and derives, this will point back to the attribute only.
     /// For the entire item use [`InFile::original_file_range_full`].
-    pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange {
+    pub fn original_file_range(self, db: &dyn db::ExpandDatabase) -> FileRange {
         match self.file_id.repr() {
             HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
             HirFileIdRepr::MacroFile(mac_file) => {
@@ -831,7 +831,7 @@ impl<'a> InFile<&'a SyntaxNode> {
     }
 
     /// Falls back to the macro call range if the node cannot be mapped up fully.
-    pub fn original_file_range_full(self, db: &dyn db::AstDatabase) -> FileRange {
+    pub fn original_file_range_full(self, db: &dyn db::ExpandDatabase) -> FileRange {
         match self.file_id.repr() {
             HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
             HirFileIdRepr::MacroFile(mac_file) => {
@@ -846,7 +846,7 @@ impl<'a> InFile<&'a SyntaxNode> {
     }
 
     /// Attempts to map the syntax node back up its macro calls.
-    pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option<FileRange> {
+    pub fn original_file_range_opt(self, db: &dyn db::ExpandDatabase) -> Option<FileRange> {
         match ascend_node_border_tokens(db, self) {
             Some(InFile { file_id, value: (first, last) }) => {
                 let original_file = file_id.original_file(db);
@@ -865,7 +865,7 @@ impl<'a> InFile<&'a SyntaxNode> {
         }
     }
 
-    pub fn original_syntax_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
+    pub fn original_syntax_node(self, db: &dyn db::ExpandDatabase) -> Option<InFile<SyntaxNode>> {
         // This kind of upmapping can only be achieved in attribute expanded files,
         // as we don't have node inputs otherwise and therefore can't find an `N` node in the input
         if !self.file_id.is_macro() {
@@ -892,13 +892,13 @@ impl<'a> InFile<&'a SyntaxNode> {
 }
 
 impl InFile<SyntaxToken> {
-    pub fn upmap(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxToken>> {
+    pub fn upmap(self, db: &dyn db::ExpandDatabase) -> Option<InFile<SyntaxToken>> {
         let expansion = self.file_id.expansion_info(db)?;
         expansion.map_token_up(db, self.as_ref()).map(|(it, _)| it)
     }
 
     /// Falls back to the macro call range if the node cannot be mapped up fully.
-    pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange {
+    pub fn original_file_range(self, db: &dyn db::ExpandDatabase) -> FileRange {
         match self.file_id.repr() {
             HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
             HirFileIdRepr::MacroFile(mac_file) => {
@@ -913,7 +913,7 @@ impl InFile<SyntaxToken> {
     }
 
     /// Attempts to map the syntax node back up its macro calls.
-    pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option<FileRange> {
+    pub fn original_file_range_opt(self, db: &dyn db::ExpandDatabase) -> Option<FileRange> {
         match self.file_id.repr() {
             HirFileIdRepr::FileId(file_id) => {
                 Some(FileRange { file_id, range: self.value.text_range() })
@@ -932,7 +932,7 @@ impl InFile<SyntaxToken> {
 
     pub fn ancestors_with_macros(
         self,
-        db: &dyn db::AstDatabase,
+        db: &dyn db::ExpandDatabase,
     ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
         self.value.parent().into_iter().flat_map({
             let file_id = self.file_id;
@@ -942,7 +942,7 @@ impl InFile<SyntaxToken> {
 }
 
 fn ascend_node_border_tokens(
-    db: &dyn db::AstDatabase,
+    db: &dyn db::ExpandDatabase,
     InFile { file_id, value: node }: InFile<&SyntaxNode>,
 ) -> Option<InFile<(SyntaxToken, SyntaxToken)>> {
     let expansion = file_id.expansion_info(db)?;
@@ -958,7 +958,7 @@ fn ascend_node_border_tokens(
 }
 
 fn ascend_call_token(
-    db: &dyn db::AstDatabase,
+    db: &dyn db::ExpandDatabase,
     expansion: &ExpansionInfo,
     token: InFile<SyntaxToken>,
 ) -> Option<InFile<SyntaxToken>> {
@@ -977,7 +977,7 @@ impl<N: AstNode> InFile<N> {
         self.value.syntax().descendants().filter_map(T::cast).map(move |n| self.with_value(n))
     }
 
-    pub fn original_ast_node(self, db: &dyn db::AstDatabase) -> Option<InFile<N>> {
+    pub fn original_ast_node(self, db: &dyn db::ExpandDatabase) -> Option<InFile<N>> {
         // This kind of upmapping can only be achieved in attribute expanded files,
         // as we don't have node inputs otherwise and therefore can't find an `N` node in the input
         if !self.file_id.is_macro() {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
index d7586d129b7..e9393cc89ae 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
@@ -6,7 +6,7 @@ use std::{
 };
 
 use crate::{
-    db::AstDatabase,
+    db::ExpandDatabase,
     hygiene::Hygiene,
     name::{known, Name},
 };
@@ -37,7 +37,11 @@ pub enum PathKind {
 }
 
 impl ModPath {
-    pub fn from_src(db: &dyn AstDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
+    pub fn from_src(
+        db: &dyn ExpandDatabase,
+        path: ast::Path,
+        hygiene: &Hygiene,
+    ) -> Option<ModPath> {
         convert_path(db, None, path, hygiene)
     }
 
@@ -162,7 +166,7 @@ impl From<Name> for ModPath {
 }
 
 fn convert_path(
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     prefix: Option<ModPath>,
     path: ast::Path,
     hygiene: &Hygiene,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
index 3f4d2540c09..d758e9302cd 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
@@ -3,22 +3,20 @@
 use base_db::{CrateId, ProcMacroExpansionError, ProcMacroId, ProcMacroKind};
 use stdx::never;
 
-use crate::{db::AstDatabase, tt, ExpandError, ExpandResult};
+use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult};
 
 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
 pub struct ProcMacroExpander {
-    krate: CrateId,
     proc_macro_id: Option<ProcMacroId>,
 }
 
 impl ProcMacroExpander {
-    pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> Self {
-        Self { krate, proc_macro_id: Some(proc_macro_id) }
+    pub fn new(proc_macro_id: ProcMacroId) -> Self {
+        Self { proc_macro_id: Some(proc_macro_id) }
     }
 
-    pub fn dummy(krate: CrateId) -> Self {
-        // FIXME: Should store the name for better errors
-        Self { krate, proc_macro_id: None }
+    pub fn dummy() -> Self {
+        Self { proc_macro_id: None }
     }
 
     pub fn is_dummy(&self) -> bool {
@@ -27,7 +25,8 @@ impl ProcMacroExpander {
 
     pub fn expand(
         self,
-        db: &dyn AstDatabase,
+        db: &dyn ExpandDatabase,
+        def_crate: CrateId,
         calling_crate: CrateId,
         tt: &tt::Subtree,
         attr_arg: Option<&tt::Subtree>,
@@ -35,7 +34,7 @@ impl ProcMacroExpander {
         match self.proc_macro_id {
             Some(id) => {
                 let krate_graph = db.crate_graph();
-                let proc_macros = match &krate_graph[self.krate].proc_macro {
+                let proc_macros = match &krate_graph[def_crate].proc_macro {
                     Ok(proc_macros) => proc_macros,
                     Err(_) => {
                         never!("Non-dummy expander even though there are no proc macros");
@@ -84,7 +83,7 @@ impl ProcMacroExpander {
             }
             None => ExpandResult::with_err(
                 tt::Subtree::empty(),
-                ExpandError::UnresolvedProcMacro(self.krate),
+                ExpandError::UnresolvedProcMacro(def_crate),
             ),
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index 4572e33486f..9b3296df250 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -22,10 +22,10 @@ either = "1.7.0"
 tracing = "0.1.35"
 rustc-hash = "1.1.0"
 scoped-tls = "1.0.0"
-chalk-solve = { version = "0.88.0", default-features = false }
-chalk-ir = "0.88.0"
-chalk-recursive = { version = "0.88.0", default-features = false }
-chalk-derive = "0.88.0"
+chalk-solve = { version = "0.89.0", default-features = false }
+chalk-ir = "0.89.0"
+chalk-recursive = { version = "0.89.0", default-features = false }
+chalk-derive = "0.89.0"
 la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
 once_cell = "1.17.0"
 typed-arena = "2.0.1"
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index e6aefbf2716..2141894922f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -12,7 +12,7 @@ use hir_def::{
 use crate::{
     db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
     from_placeholder_idx, to_chalk_trait_id, utils::generics, AdtId, AliasEq, AliasTy, Binders,
-    CallableDefId, CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy,
+    CallableDefId, CallableSig, DynTy, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy,
     QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause,
 };
 
@@ -378,6 +378,19 @@ impl ProjectionTyExt for ProjectionTy {
     }
 }
 
+pub trait DynTyExt {
+    fn principal(&self) -> Option<&TraitRef>;
+}
+
+impl DynTyExt for DynTy {
+    fn principal(&self) -> Option<&TraitRef> {
+        self.bounds.skip_binders().interned().get(0).and_then(|b| match b.skip_binders() {
+            crate::WhereClause::Implemented(trait_ref) => Some(trait_ref),
+            _ => None,
+        })
+    }
+}
+
 pub trait TraitRefExt {
     fn hir_trait_id(&self) -> TraitId;
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs
index 37eb06be1d3..4b147b99707 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs
@@ -11,3 +11,9 @@ pub use crate::diagnostics::{
     },
     unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr},
 };
+
+#[derive(Debug, PartialEq, Eq)]
+pub struct IncoherentImpl {
+    pub file_id: hir_expand::HirFileId,
+    pub impl_: syntax::AstPtr<syntax::ast::Impl>,
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 535189ff028..ee186673ee1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -275,7 +275,23 @@ impl<'a> InferenceContext<'a> {
                     Some(type_ref) => self.make_ty(type_ref),
                     None => self.table.new_type_var(),
                 };
-                sig_tys.push(ret_ty.clone());
+                if let ClosureKind::Async = closure_kind {
+                    // Use the first type parameter as the output type of future.
+                    // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
+                    let impl_trait_id =
+                        crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
+                    let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
+                    sig_tys.push(
+                        TyKind::OpaqueType(
+                            opaque_ty_id,
+                            Substitution::from1(Interner, ret_ty.clone()),
+                        )
+                        .intern(Interner),
+                    );
+                } else {
+                    sig_tys.push(ret_ty.clone());
+                }
+
                 let sig_ty = TyKind::Function(FnPointer {
                     num_binders: 0,
                     sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
@@ -286,33 +302,38 @@ impl<'a> InferenceContext<'a> {
                 })
                 .intern(Interner);
 
-                let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) {
-                    // FIXME: report error when there are more than 1 parameter.
-                    let resume_ty = match sig_tys.first() {
-                        // When `sig_tys.len() == 1` the first type is the return type, not the
-                        // first parameter type.
-                        Some(ty) if sig_tys.len() > 1 => ty.clone(),
-                        _ => self.result.standard_types.unit.clone(),
-                    };
-                    let yield_ty = self.table.new_type_var();
-
-                    let subst = TyBuilder::subst_for_generator(self.db, self.owner)
-                        .push(resume_ty.clone())
-                        .push(yield_ty.clone())
-                        .push(ret_ty.clone())
-                        .build();
+                let (ty, resume_yield_tys) = match closure_kind {
+                    ClosureKind::Generator(_) => {
+                        // FIXME: report error when there are more than 1 parameter.
+                        let resume_ty = match sig_tys.first() {
+                            // When `sig_tys.len() == 1` the first type is the return type, not the
+                            // first parameter type.
+                            Some(ty) if sig_tys.len() > 1 => ty.clone(),
+                            _ => self.result.standard_types.unit.clone(),
+                        };
+                        let yield_ty = self.table.new_type_var();
+
+                        let subst = TyBuilder::subst_for_generator(self.db, self.owner)
+                            .push(resume_ty.clone())
+                            .push(yield_ty.clone())
+                            .push(ret_ty.clone())
+                            .build();
 
-                    let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
-                    let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
+                        let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
+                        let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
 
-                    (generator_ty, Some((resume_ty, yield_ty)))
-                } else {
-                    let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
-                    let closure_ty =
-                        TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
-                            .intern(Interner);
+                        (generator_ty, Some((resume_ty, yield_ty)))
+                    }
+                    ClosureKind::Closure | ClosureKind::Async => {
+                        let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
+                        let closure_ty = TyKind::Closure(
+                            closure_id,
+                            Substitution::from1(Interner, sig_ty.clone()),
+                        )
+                        .intern(Interner);
 
-                    (closure_ty, None)
+                        (closure_ty, None)
+                    }
                 };
 
                 // Eagerly try to relate the closure type with the expected
@@ -321,7 +342,7 @@ impl<'a> InferenceContext<'a> {
                 self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected);
 
                 // Now go through the argument patterns
-                for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
+                for (arg_pat, arg_ty) in args.iter().zip(&sig_tys) {
                     self.infer_top_pat(*arg_pat, &arg_ty);
                 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index 0f49e837881..5f839fc307a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -5,10 +5,7 @@ use std::iter::repeat_with;
 use chalk_ir::Mutability;
 use hir_def::{
     body::Body,
-    expr::{
-        Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId,
-        RecordFieldPat,
-    },
+    expr::{Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId},
     path::Path,
 };
 use hir_expand::name::Name;
@@ -439,38 +436,8 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
 
 pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool {
     let mut res = false;
-    walk_pats(body, pat_id, &mut |pat| {
+    body.walk_pats(pat_id, &mut |pat| {
         res |= matches!(pat, Pat::Bind { id, .. } if body.bindings[*id].mode == BindingAnnotation::Ref);
     });
     res
 }
-
-fn walk_pats(body: &Body, pat_id: PatId, f: &mut impl FnMut(&Pat)) {
-    let pat = &body[pat_id];
-    f(pat);
-    match pat {
-        Pat::Range { .. }
-        | Pat::Lit(..)
-        | Pat::Path(..)
-        | Pat::ConstBlock(..)
-        | Pat::Wild
-        | Pat::Missing => {}
-        &Pat::Bind { subpat, .. } => {
-            if let Some(subpat) = subpat {
-                walk_pats(body, subpat, f);
-            }
-        }
-        Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
-            args.iter().copied().for_each(|p| walk_pats(body, p, f));
-        }
-        Pat::Ref { pat, .. } => walk_pats(body, *pat, f),
-        Pat::Slice { prefix, slice, suffix } => {
-            let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
-            total_iter.copied().for_each(|p| walk_pats(body, p, f));
-        }
-        Pat::Record { args, .. } => {
-            args.iter().for_each(|RecordFieldPat { pat, .. }| walk_pats(body, *pat, f));
-        }
-        Pat::Box { inner } => walk_pats(body, *inner, f),
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 92a17fc3a99..f3a27632bf5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -19,13 +19,13 @@ use stdx::never;
 use crate::{
     autoderef::{self, AutoderefKind},
     db::HirDatabase,
-    from_foreign_def_id,
+    from_chalk_trait_id, from_foreign_def_id,
     infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
     primitive::{FloatTy, IntTy, UintTy},
     static_lifetime, to_chalk_trait_id,
     utils::all_super_traits,
-    AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
-    Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
+    AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, InEnvironment,
+    Interner, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
 };
 
 /// This is used as a key for indexing impls.
@@ -266,11 +266,12 @@ impl TraitImpls {
 #[derive(Debug, Eq, PartialEq)]
 pub struct InherentImpls {
     map: FxHashMap<TyFingerprint, Vec<ImplId>>,
+    invalid_impls: Vec<ImplId>,
 }
 
 impl InherentImpls {
     pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
-        let mut impls = Self { map: FxHashMap::default() };
+        let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
 
         let crate_def_map = db.crate_def_map(krate);
         impls.collect_def_map(db, &crate_def_map);
@@ -283,7 +284,7 @@ impl InherentImpls {
         db: &dyn HirDatabase,
         block: BlockId,
     ) -> Option<Arc<Self>> {
-        let mut impls = Self { map: FxHashMap::default() };
+        let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
         if let Some(block_def_map) = db.block_def_map(block) {
             impls.collect_def_map(db, &block_def_map);
             impls.shrink_to_fit();
@@ -306,11 +307,17 @@ impl InherentImpls {
                 }
 
                 let self_ty = db.impl_self_ty(impl_id);
-                let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
-                if let Some(fp) = fp {
-                    self.map.entry(fp).or_default().push(impl_id);
+                let self_ty = self_ty.skip_binders();
+
+                match is_inherent_impl_coherent(db, def_map, &data, self_ty) {
+                    true => {
+                        // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
+                        if let Some(fp) = TyFingerprint::for_inherent_impl(self_ty) {
+                            self.map.entry(fp).or_default().push(impl_id);
+                        }
+                    }
+                    false => self.invalid_impls.push(impl_id),
                 }
-                // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
             }
 
             // To better support custom derives, collect impls in all unnamed const items.
@@ -334,6 +341,10 @@ impl InherentImpls {
     pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
         self.map.values().flat_map(|v| v.iter().copied())
     }
+
+    pub fn invalid_impls(&self) -> &[ImplId] {
+        &self.invalid_impls
+    }
 }
 
 pub(crate) fn incoherent_inherent_impl_crates(
@@ -775,6 +786,69 @@ fn find_matching_impl(
     }
 }
 
+fn is_inherent_impl_coherent(
+    db: &dyn HirDatabase,
+    def_map: &DefMap,
+    impl_data: &ImplData,
+    self_ty: &Ty,
+) -> bool {
+    let self_ty = self_ty.kind(Interner);
+    let impl_allowed = match self_ty {
+        TyKind::Tuple(_, _)
+        | TyKind::FnDef(_, _)
+        | TyKind::Array(_, _)
+        | TyKind::Never
+        | TyKind::Raw(_, _)
+        | TyKind::Ref(_, _, _)
+        | TyKind::Slice(_)
+        | TyKind::Str
+        | TyKind::Scalar(_) => def_map.is_rustc_coherence_is_core(),
+
+        &TyKind::Adt(AdtId(adt), _) => adt.module(db.upcast()).krate() == def_map.krate(),
+        TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| {
+            from_chalk_trait_id(trait_ref.trait_id).module(db.upcast()).krate() == def_map.krate()
+        }),
+
+        _ => true,
+    };
+    impl_allowed || {
+        let rustc_has_incoherent_inherent_impls = match self_ty {
+            TyKind::Tuple(_, _)
+            | TyKind::FnDef(_, _)
+            | TyKind::Array(_, _)
+            | TyKind::Never
+            | TyKind::Raw(_, _)
+            | TyKind::Ref(_, _, _)
+            | TyKind::Slice(_)
+            | TyKind::Str
+            | TyKind::Scalar(_) => true,
+
+            &TyKind::Adt(AdtId(adt), _) => match adt {
+                hir_def::AdtId::StructId(it) => {
+                    db.struct_data(it).rustc_has_incoherent_inherent_impls
+                }
+                hir_def::AdtId::UnionId(it) => {
+                    db.union_data(it).rustc_has_incoherent_inherent_impls
+                }
+                hir_def::AdtId::EnumId(it) => db.enum_data(it).rustc_has_incoherent_inherent_impls,
+            },
+            TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| {
+                db.trait_data(from_chalk_trait_id(trait_ref.trait_id))
+                    .rustc_has_incoherent_inherent_impls
+            }),
+
+            _ => false,
+        };
+        rustc_has_incoherent_inherent_impls
+            && !impl_data.items.is_empty()
+            && impl_data.items.iter().copied().all(|assoc| match assoc {
+                AssocItemId::FunctionId(it) => db.function_data(it).rustc_allow_incoherent_impl,
+                AssocItemId::ConstId(it) => db.const_data(it).rustc_allow_incoherent_impl,
+                AssocItemId::TypeAliasId(it) => db.type_alias_data(it).rustc_allow_incoherent_impl,
+            })
+    }
+}
+
 pub fn iterate_path_candidates(
     ty: &Canonical<Ty>,
     db: &dyn HirDatabase,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 435a914088b..c4dd7c0ace4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -1113,7 +1113,7 @@ impl MirLowerCtx<'_> {
                 if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) {
                     binding_mode = mode;
                 }
-                self.push_storage_live(*id, current)?;
+                self.push_storage_live(*id, current);
                 self.push_assignment(
                     current,
                     target_place.into(),
@@ -1327,8 +1327,9 @@ impl MirLowerCtx<'_> {
         is_ty_uninhabited_from(&self.infer[expr_id], self.owner.module(self.db.upcast()), self.db)
     }
 
-    /// This function push `StorageLive` statements for each binding in the pattern.
-    fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) -> Result<()> {
+    /// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` in
+    /// the appropriated places.
+    fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) {
         // Current implementation is wrong. It adds no `StorageDead` at the end of scope, and before each break
         // and continue. It just add a `StorageDead` before the `StorageLive`, which is not wrong, but unneeeded in
         // the proper implementation. Due this limitation, implementing a borrow checker on top of this mir will falsely
@@ -1356,7 +1357,6 @@ impl MirLowerCtx<'_> {
         let l = self.result.binding_locals[b];
         self.push_statement(current, StatementKind::StorageDead(l).with_span(span));
         self.push_statement(current, StatementKind::StorageLive(l).with_span(span));
-        Ok(())
     }
 
     fn resolve_lang_item(&self, item: LangItem) -> Result<LangItemTarget> {
@@ -1381,10 +1381,10 @@ impl MirLowerCtx<'_> {
                     if let Some(expr_id) = initializer {
                         let else_block;
                         let Some((init_place, c)) =
-                        self.lower_expr_as_place(current, *expr_id, true)?
-                    else {
-                        return Ok(None);
-                    };
+                            self.lower_expr_as_place(current, *expr_id, true)?
+                        else {
+                            return Ok(None);
+                        };
                         current = c;
                         (current, else_block) = self.pattern_match(
                             current,
@@ -1407,6 +1407,10 @@ impl MirLowerCtx<'_> {
                                 }
                             }
                         }
+                    } else {
+                        self.body.walk_bindings_in_pat(*pat, |b| {
+                            self.push_storage_live(b, current);
+                        });
                     }
                 }
                 hir_def::expr::Statement::Expr { expr, has_semi: _ } => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
index 118e5311e9a..8c48331b94b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
@@ -9,7 +9,7 @@ use base_db::{
     salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast,
 };
 use hir_def::{db::DefDatabase, ModuleId};
-use hir_expand::db::AstDatabase;
+use hir_expand::db::ExpandDatabase;
 use stdx::hash::{NoHashHashMap, NoHashHashSet};
 use syntax::TextRange;
 use test_utils::extract_annotations;
@@ -17,7 +17,7 @@ use test_utils::extract_annotations;
 #[salsa::database(
     base_db::SourceDatabaseExtStorage,
     base_db::SourceDatabaseStorage,
-    hir_expand::db::AstDatabaseStorage,
+    hir_expand::db::ExpandDatabaseStorage,
     hir_def::db::InternDatabaseStorage,
     hir_def::db::DefDatabaseStorage,
     crate::db::HirDatabaseStorage
@@ -41,8 +41,8 @@ impl fmt::Debug for TestDB {
     }
 }
 
-impl Upcast<dyn AstDatabase> for TestDB {
-    fn upcast(&self) -> &(dyn AstDatabase + 'static) {
+impl Upcast<dyn ExpandDatabase> for TestDB {
+    fn upcast(&self) -> &(dyn ExpandDatabase + 'static) {
         &*self
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
index bcd63d9472a..83d31f002a1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -23,7 +23,7 @@ use hir_def::{
     src::HasSource,
     AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId,
 };
-use hir_expand::{db::AstDatabase, InFile};
+use hir_expand::{db::ExpandDatabase, InFile};
 use once_cell::race::OnceBool;
 use stdx::format_to;
 use syntax::{
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index e568e7013fa..378d4783361 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -9,6 +9,7 @@ fn infer_slice_method() {
     check_types(
         r#"
 impl<T> [T] {
+    #[rustc_allow_incoherent_impl]
     fn foo(&self) -> T {
         loop {}
     }
@@ -35,6 +36,7 @@ fn test() {
 //- /lib.rs crate:other_crate
 mod foo {
     impl f32 {
+        #[rustc_allow_incoherent_impl]
         pub fn foo(self) -> f32 { 0. }
     }
 }
@@ -47,6 +49,7 @@ fn infer_array_inherent_impl() {
     check_types(
         r#"
 impl<T, const N: usize> [T; N] {
+    #[rustc_allow_incoherent_impl]
     fn foo(&self) -> T {
         loop {}
     }
@@ -1437,6 +1440,7 @@ fn resolve_const_generic_array_methods() {
         r#"
 #[lang = "array"]
 impl<T, const N: usize> [T; N] {
+    #[rustc_allow_incoherent_impl]
     pub fn map<F, U>(self, f: F) -> [U; N]
     where
         F: FnMut(T) -> U,
@@ -1445,6 +1449,7 @@ impl<T, const N: usize> [T; N] {
 
 #[lang = "slice"]
 impl<T> [T] {
+    #[rustc_allow_incoherent_impl]
     pub fn map<F, U>(self, f: F) -> &[U]
     where
         F: FnMut(T) -> U,
@@ -1468,6 +1473,7 @@ struct Const<const N: usize>;
 
 #[lang = "array"]
 impl<T, const N: usize> [T; N] {
+    #[rustc_allow_incoherent_impl]
     pub fn my_map<F, U, const X: usize>(self, f: F, c: Const<X>) -> [U; X]
     where
         F: FnMut(T) -> U,
@@ -1476,6 +1482,7 @@ impl<T, const N: usize> [T; N] {
 
 #[lang = "slice"]
 impl<T> [T] {
+    #[rustc_allow_incoherent_impl]
     pub fn my_map<F, const X: usize, U>(self, f: F, c: Const<X>) -> &[U]
     where
         F: FnMut(T) -> U,
@@ -1874,14 +1881,14 @@ fn incoherent_impls() {
 pub struct Box<T>(T);
 use core::error::Error;
 
-#[rustc_allow_incoherent_impl]
 impl dyn Error {
+    #[rustc_allow_incoherent_impl]
     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
         loop {}
     }
 }
-#[rustc_allow_incoherent_impl]
 impl dyn Error + Send {
+    #[rustc_allow_incoherent_impl]
     /// Attempts to downcast the box to a concrete type.
     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
         let err: Box<dyn Error> = self;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index e6b4f13c8d1..689f0da44f6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -1756,3 +1756,35 @@ const C: usize = 2 + 2;
 "#,
     );
 }
+
+#[test]
+fn regression_14164() {
+    check_types(
+        r#"
+trait Rec {
+    type K;
+    type Rebind<Tok>: Rec<K = Tok>;
+}
+
+trait Expr<K> {
+    type Part: Rec<K = K>;
+    fn foo(_: <Self::Part as Rec>::Rebind<i32>) {}
+}
+
+struct Head<K>(K);
+impl<K> Rec for Head<K> {
+    type K = K;
+    type Rebind<Tok> = Head<Tok>;
+}
+
+fn test<E>()
+where
+    E: Expr<usize, Part = Head<usize>>,
+{
+    let head;
+      //^^^^ Head<i32>
+    E::foo(head);
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index 0e9c349afef..13cc3fea52d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -1116,21 +1116,22 @@ fn infer_inherent_method() {
 fn infer_inherent_method_str() {
     check_infer(
         r#"
-        #[lang = "str"]
-        impl str {
-            fn foo(&self) -> i32 {}
-        }
+#![rustc_coherence_is_core]
+#[lang = "str"]
+impl str {
+    fn foo(&self) -> i32 {}
+}
 
-        fn test() {
-            "foo".foo();
-        }
-        "#,
+fn test() {
+    "foo".foo();
+}
+"#,
         expect![[r#"
-            39..43 'self': &str
-            52..54 '{}': i32
-            68..88 '{     ...o(); }': ()
-            74..79 '"foo"': &str
-            74..85 '"foo".foo()': i32
+            67..71 'self': &str
+            80..82 '{}': i32
+            96..116 '{     ...o(); }': ()
+            102..107 '"foo"': &str
+            102..113 '"foo".foo()': i32
         "#]],
     );
 }
@@ -2640,6 +2641,7 @@ impl<T> [T] {}
 
 #[lang = "slice_alloc"]
 impl<T> [T] {
+    #[rustc_allow_incoherent_impl]
     pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
         unimplemented!()
     }
@@ -2655,22 +2657,22 @@ struct Astruct;
 impl B for Astruct {}
 "#,
         expect![[r#"
-            569..573 'self': Box<[T], A>
-            602..634 '{     ...     }': Vec<T, A>
-            648..761 '{     ...t]); }': ()
-            658..661 'vec': Vec<i32, Global>
-            664..679 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
-            664..691 '<[_]>:...1i32])': Vec<i32, Global>
-            680..690 'box [1i32]': Box<[i32; 1], Global>
-            684..690 '[1i32]': [i32; 1]
-            685..689 '1i32': i32
-            701..702 'v': Vec<Box<dyn B, Global>, Global>
-            722..739 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
-            722..758 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global>
-            740..757 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global>
-            744..757 '[box Astruct]': [Box<dyn B, Global>; 1]
-            745..756 'box Astruct': Box<Astruct, Global>
-            749..756 'Astruct': Astruct
+            604..608 'self': Box<[T], A>
+            637..669 '{     ...     }': Vec<T, A>
+            683..796 '{     ...t]); }': ()
+            693..696 'vec': Vec<i32, Global>
+            699..714 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
+            699..726 '<[_]>:...1i32])': Vec<i32, Global>
+            715..725 'box [1i32]': Box<[i32; 1], Global>
+            719..725 '[1i32]': [i32; 1]
+            720..724 '1i32': i32
+            736..737 'v': Vec<Box<dyn B, Global>, Global>
+            757..774 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
+            757..793 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global>
+            775..792 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global>
+            779..792 '[box Astruct]': [Box<dyn B, Global>; 1]
+            780..791 'box Astruct': Box<Astruct, Global>
+            784..791 'Astruct': Astruct
         "#]],
     )
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 015085bde45..da76d7fd83f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -83,6 +83,46 @@ async fn test() {
 }
 
 #[test]
+fn infer_async_closure() {
+    check_types(
+        r#"
+//- minicore: future, option
+async fn test() {
+    let f = async move |x: i32| x + 42;
+    f;
+//  ^ |i32| -> impl Future<Output = i32>
+    let a = f(4);
+    a;
+//  ^ impl Future<Output = i32>
+    let x = a.await;
+    x;
+//  ^ i32
+    let f = async move || 42;
+    f;
+//  ^ || -> impl Future<Output = i32>
+    let a = f();
+    a;
+//  ^ impl Future<Output = i32>
+    let x = a.await;
+    x;
+//  ^ i32
+    let b = ((async move || {})()).await;
+    b;
+//  ^ ()
+    let c = async move || {
+        let y = None;
+        y
+    //  ^ Option<u64>
+    };
+    let _: Option<u64> = c().await;
+    c;
+//  ^ || -> impl Future<Output = Option<u64>>
+}
+"#,
+    );
+}
+
+#[test]
 fn auto_sized_async_block() {
     check_no_mismatches(
         r#"
@@ -493,29 +533,30 @@ fn tuple_struct_with_fn() {
         r#"
 struct S(fn(u32) -> u64);
 fn test() -> u64 {
-    let a = S(|i| 2*i);
+    let a = S(|i| 2*i as u64);
     let b = a.0(4);
     a.0(2)
 }"#,
         expect![[r#"
-            43..101 '{     ...0(2) }': u64
+            43..108 '{     ...0(2) }': u64
             53..54 'a': S
             57..58 'S': S(fn(u32) -> u64) -> S
-            57..67 'S(|i| 2*i)': S
-            59..66 '|i| 2*i': |u32| -> u64
+            57..74 'S(|i| ...s u64)': S
+            59..73 '|i| 2*i as u64': |u32| -> u64
             60..61 'i': u32
-            63..64 '2': u32
-            63..66 '2*i': u32
+            63..64 '2': u64
+            63..73 '2*i as u64': u64
             65..66 'i': u32
-            77..78 'b': u64
-            81..82 'a': S
-            81..84 'a.0': fn(u32) -> u64
-            81..87 'a.0(4)': u64
-            85..86 '4': u32
-            93..94 'a': S
-            93..96 'a.0': fn(u32) -> u64
-            93..99 'a.0(2)': u64
-            97..98 '2': u32
+            65..73 'i as u64': u64
+            84..85 'b': u64
+            88..89 'a': S
+            88..91 'a.0': fn(u32) -> u64
+            88..94 'a.0(4)': u64
+            92..93 '4': u32
+            100..101 'a': S
+            100..103 'a.0': fn(u32) -> u64
+            100..106 'a.0(2)': u64
+            104..105 '2': u32
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs
index cd465739139..0935b5ea519 100644
--- a/src/tools/rust-analyzer/crates/hir/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/db.rs
@@ -5,7 +5,7 @@
 //! But we need this for at least LRU caching at the query level.
 pub use hir_def::db::*;
 pub use hir_expand::db::{
-    AstDatabase, AstDatabaseStorage, AstIdMapQuery, ExpandProcMacroQuery, HygieneFrameQuery,
+    AstIdMapQuery, ExpandDatabase, ExpandDatabaseStorage, ExpandProcMacroQuery, HygieneFrameQuery,
     InternMacroCallQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandErrorQuery,
     MacroExpandQuery, ParseMacroExpansionQuery,
 };
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 8f019a81b2d..253d62dafc6 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -3,6 +3,8 @@
 //!
 //! This probably isn't the best way to do this -- ideally, diagnostics should
 //! be expressed in terms of hir types themselves.
+pub use hir_ty::diagnostics::{IncoherentImpl, IncorrectCase};
+
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
@@ -35,6 +37,7 @@ diagnostics![
     InactiveCode,
     IncorrectCase,
     InvalidDeriveTarget,
+    IncoherentImpl,
     MacroError,
     MalformedDerive,
     MismatchedArgCount,
@@ -220,5 +223,3 @@ pub struct NeedMut {
 pub struct UnusedMut {
     pub local: Local,
 }
-
-pub use hir_ty::diagnostics::IncorrectCase;
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 25c07a2fbd3..35424feec8b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -85,10 +85,10 @@ use crate::db::{DefDatabase, HirDatabase};
 pub use crate::{
     attrs::{HasAttrs, Namespace},
     diagnostics::{
-        AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncorrectCase,
-        InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
-        MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem, PrivateField,
-        ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro,
+        AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl,
+        IncorrectCase, InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount,
+        MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem,
+        PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro,
         UnresolvedExternCrate, UnresolvedField, UnresolvedImport, UnresolvedMacroCall,
         UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro, UnusedMut,
     },
@@ -604,11 +604,23 @@ impl Module {
             }
         }
 
+        let inherent_impls = db.inherent_impls_in_crate(self.id.krate());
+
         for impl_def in self.impl_defs(db) {
             for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() {
                 emit_def_diagnostic(db, acc, diag);
             }
 
+            if inherent_impls.invalid_impls().contains(&impl_def.id) {
+                let loc = impl_def.id.lookup(db.upcast());
+                let tree = loc.id.item_tree(db.upcast());
+                let node = &tree[loc.id.value];
+                let file_id = loc.id.file_id();
+                let ast_id_map = db.ast_id_map(file_id);
+
+                acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into())
+            }
+
             for item in impl_def.items(db) {
                 let def: DefWithBody = match item {
                     AssocItem::Function(it) => it.into(),
@@ -3210,6 +3222,14 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
     }
 
+    pub fn is_float(&self) -> bool {
+        matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Float(_)))
+    }
+
+    pub fn is_char(&self) -> bool {
+        matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Char))
+    }
+
     pub fn is_int_or_uint(&self) -> bool {
         match self.ty.kind(Interner) {
             TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)) => true,
@@ -3224,6 +3244,13 @@ impl Type {
         }
     }
 
+    pub fn as_slice(&self) -> Option<Type> {
+        match &self.ty.kind(Interner) {
+            TyKind::Slice(ty) => Some(self.derived(ty.clone())),
+            _ => None,
+        }
+    }
+
     pub fn strip_references(&self) -> Type {
         self.derived(self.ty.strip_references().clone())
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 8bd905d0113..407ba6f6584 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -15,7 +15,7 @@ use hir_def::{
     AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId,
 };
 use hir_expand::{
-    db::AstDatabase,
+    db::ExpandDatabase,
     name::{known, AsName},
     ExpansionInfo, MacroCallId,
 };
@@ -411,7 +411,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.resolve_record_field(field)
     }
 
-    pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> {
+    pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> {
         self.imp.resolve_record_pat_field(field)
     }
 
@@ -1201,7 +1201,7 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(field.syntax())?.resolve_record_field(self.db, field)
     }
 
-    fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> {
+    fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> {
         self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field)
     }
 
@@ -1536,7 +1536,7 @@ impl<'db> SemanticsImpl<'db> {
 
 fn macro_call_to_macro_id(
     ctx: &mut SourceToDefCtx<'_, '_>,
-    db: &dyn AstDatabase,
+    db: &dyn ExpandDatabase,
     macro_call_id: MacroCallId,
 ) -> Option<MacroId> {
     let loc = db.lookup_intern_macro_call(macro_call_id);
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 133fa810d66..c24d196e1b6 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -441,14 +441,17 @@ impl SourceAnalyzer {
         &self,
         db: &dyn HirDatabase,
         field: &ast::RecordPatField,
-    ) -> Option<Field> {
+    ) -> Option<(Field, Type)> {
         let field_name = field.field_name()?.as_name();
         let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
         let pat_id = self.pat_id(&record_pat.into())?;
         let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?;
         let variant_data = variant.variant_data(db.upcast());
         let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
-        Some(field.into())
+        let (_, subst) = self.infer.as_ref()?.type_of_pat.get(pat_id)?.as_adt()?;
+        let field_ty =
+            db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
+        Some((field.into(), Type::new_with_resolver(db, &self.resolver, field_ty)))
     }
 
     pub(crate) fn resolve_macro_call(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index eef037f9875..0768389281c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -1027,7 +1027,7 @@ fn next_space_for_fn_after_call_site(expr: ast::CallableExpr) -> Option<Generate
 }
 
 fn next_space_for_fn_in_module(
-    db: &dyn hir::db::AstDatabase,
+    db: &dyn hir::db::ExpandDatabase,
     module_source: &hir::InFile<hir::ModuleSource>,
 ) -> Option<(FileId, GeneratedFunctionTarget)> {
     let file = module_source.file_id.original_file(db);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
index 5ac18727c19..28d815e81b4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
@@ -363,10 +363,10 @@ fn inline(
         .collect();
 
     if function.self_param(sema.db).is_some() {
-        let this = || make::name_ref("this").syntax().clone_for_update();
+        let this = || make::name_ref("this").syntax().clone_for_update().first_token().unwrap();
         if let Some(self_local) = params[0].2.as_local(sema.db) {
             usages_for_locals(self_local)
-                .flat_map(|FileReference { name, range, .. }| match name {
+                .filter_map(|FileReference { name, range, .. }| match name {
                     ast::NameLike::NameRef(_) => Some(body.syntax().covering_element(range)),
                     _ => None,
                 })
@@ -691,6 +691,42 @@ fn main() {
     }
 
     #[test]
+    fn generic_method_by_ref() {
+        check_assist(
+            inline_call,
+            r#"
+struct Foo(u32);
+
+impl Foo {
+    fn add<T>(&self, a: u32) -> Self {
+        Foo(self.0 + a)
+    }
+}
+
+fn main() {
+    let x = Foo(3).add$0::<usize>(2);
+}
+"#,
+            r#"
+struct Foo(u32);
+
+impl Foo {
+    fn add<T>(&self, a: u32) -> Self {
+        Foo(self.0 + a)
+    }
+}
+
+fn main() {
+    let x = {
+        let ref this = Foo(3);
+        Foo(this.0 + 2)
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
     fn method_by_ref_mut() {
         check_assist(
             inline_call,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
index 1361cdf00cc..a403d5bc672 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -46,7 +46,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
     acc.add(
         AssistId("remove_dbg", AssistKind::Refactor),
         "Remove dbg!()",
-        ctx.selection_trimmed(),
+        replacements.iter().map(|&(range, _)| range).reduce(|acc, range| acc.cover(range)).unwrap(),
         |builder| {
             for (range, expr) in replacements {
                 if let Some(expr) = expr {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index 4d489b62b5c..8b07e29a587 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -265,7 +265,6 @@ mod handlers {
             inline_local_variable::inline_local_variable,
             inline_type_alias::inline_type_alias,
             inline_type_alias::inline_type_alias_uses,
-            inline_macro::inline_macro,
             introduce_named_generic::introduce_named_generic,
             introduce_named_lifetime::introduce_named_lifetime,
             invert_if::invert_if,
@@ -286,7 +285,6 @@ mod handlers {
             raw_string::add_hash,
             raw_string::make_usual_string,
             raw_string::remove_hash,
-            remove_dbg::remove_dbg,
             remove_mut::remove_mut,
             remove_unused_param::remove_unused_param,
             remove_parentheses::remove_parentheses,
@@ -335,6 +333,9 @@ mod handlers {
             generate_setter::generate_setter,
             generate_delegate_methods::generate_delegate_methods,
             generate_deref::generate_deref,
+            //
+            remove_dbg::remove_dbg,
+            inline_macro::inline_macro,
             // Are you sure you want to add new assist here, and not to the
             // sorted list above?
         ]
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
index eb87d6c5826..c3136f6df4b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -23,7 +23,7 @@ pub(crate) mod env_vars;
 
 use std::iter;
 
-use hir::{known, ScopeDef};
+use hir::{known, ScopeDef, Variant};
 use ide_db::{imports::import_assets::LocatedImport, SymbolKind};
 use syntax::ast;
 
@@ -537,17 +537,20 @@ fn enum_variants_with_paths(
     impl_: &Option<ast::Impl>,
     cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath),
 ) {
+    let mut process_variant = |variant: Variant| {
+        let self_path = hir::ModPath::from_segments(
+            hir::PathKind::Plain,
+            iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))),
+        );
+
+        cb(acc, ctx, variant, self_path);
+    };
+
     let variants = enum_.variants(ctx.db);
 
     if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) {
         if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) {
-            for &variant in &variants {
-                let self_path = hir::ModPath::from_segments(
-                    hir::PathKind::Plain,
-                    iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))),
-                );
-                cb(acc, ctx, variant, self_path);
-            }
+            variants.iter().for_each(|variant| process_variant(*variant));
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
index 09ac57153ae..77246379e7b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
@@ -415,7 +415,6 @@ fn foo(a: lib::A) { a.$0 }
     fn test_local_impls() {
         check(
             r#"
-//- /lib.rs crate:lib
 pub struct A {}
 mod m {
     impl super::A {
@@ -427,9 +426,8 @@ mod m {
         }
     }
 }
-//- /main.rs crate:main deps:lib
-fn foo(a: lib::A) {
-    impl lib::A {
+fn foo(a: A) {
+    impl A {
         fn local_method(&self) {}
     }
     a.$0
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 7dc29c3d5ac..8cbf89e9c30 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -220,6 +220,8 @@ pub(super) struct PatternContext {
     /// The record pattern this name or ref is a field of
     pub(super) record_pat: Option<ast::RecordPat>,
     pub(super) impl_: Option<ast::Impl>,
+    /// List of missing variants in a match expr
+    pub(super) missing_variants: Vec<hir::Variant>,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index db0045aef6e..a94c404586b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -1,7 +1,7 @@
 //! Module responsible for analyzing the code surrounding the cursor for completion.
 use std::iter;
 
-use hir::{Semantics, Type, TypeInfo};
+use hir::{Semantics, Type, TypeInfo, Variant};
 use ide_db::{active_parameter::ActiveParameter, RootDatabase};
 use syntax::{
     algo::{find_node_at_offset, non_trivia_sibling},
@@ -353,7 +353,7 @@ fn expected_type_and_name(
         _ => ty,
     };
 
-    loop {
+    let (ty, name) = loop {
         break match_ast! {
             match node {
                 ast::LetStmt(it) => {
@@ -385,9 +385,7 @@ fn expected_type_and_name(
                        token.clone(),
                     ).map(|ap| {
                         let name = ap.ident().map(NameOrNameRef::Name);
-
-                        let ty = strip_refs(ap.ty);
-                        (Some(ty), name)
+                        (Some(ap.ty), name)
                     })
                     .unwrap_or((None, None))
                 },
@@ -489,7 +487,8 @@ fn expected_type_and_name(
                 },
             }
         };
-    }
+    };
+    (ty.map(strip_refs), name)
 }
 
 fn classify_lifetime(
@@ -1133,6 +1132,9 @@ fn pattern_context_for(
     pat: ast::Pat,
 ) -> PatternContext {
     let mut param_ctx = None;
+
+    let mut missing_variants = vec![];
+
     let (refutability, has_type_ascription) =
     pat
         .syntax()
@@ -1162,7 +1164,52 @@ fn pattern_context_for(
                         })();
                         return (PatternRefutability::Irrefutable, has_type_ascription)
                     },
-                    ast::MatchArm(_) => PatternRefutability::Refutable,
+                    ast::MatchArm(match_arm) => {
+                       let missing_variants_opt = match_arm
+                            .syntax()
+                            .parent()
+                            .and_then(ast::MatchArmList::cast)
+                            .and_then(|match_arm_list| {
+                                match_arm_list
+                                .syntax()
+                                .parent()
+                                .and_then(ast::MatchExpr::cast)
+                                .and_then(|match_expr| {
+                                    let expr_opt = find_opt_node_in_file(&original_file, match_expr.expr());
+
+                                    expr_opt.and_then(|expr| {
+                                        sema.type_of_expr(&expr)?
+                                        .adjusted()
+                                        .autoderef(sema.db)
+                                        .find_map(|ty| match ty.as_adt() {
+                                            Some(hir::Adt::Enum(e)) => Some(e),
+                                            _ => None,
+                                        }).and_then(|enum_| {
+                                            Some(enum_.variants(sema.db))
+                                        })
+                                    })
+                                }).and_then(|variants| {
+                                   Some(variants.iter().filter_map(|variant| {
+                                        let variant_name = variant.name(sema.db).to_string();
+
+                                        let variant_already_present = match_arm_list.arms().any(|arm| {
+                                            arm.pat().and_then(|pat| {
+                                                let pat_already_present = pat.syntax().to_string().contains(&variant_name);
+                                                pat_already_present.then(|| pat_already_present)
+                                            }).is_some()
+                                        });
+
+                                        (!variant_already_present).then_some(variant.clone())
+                                    }).collect::<Vec<Variant>>())
+                                })
+                        });
+
+                        if let Some(missing_variants_) = missing_variants_opt {
+                            missing_variants = missing_variants_;
+                        };
+
+                        PatternRefutability::Refutable
+                    },
                     ast::LetExpr(_) => PatternRefutability::Refutable,
                     ast::ForExpr(_) => PatternRefutability::Irrefutable,
                     _ => PatternRefutability::Irrefutable,
@@ -1184,6 +1231,7 @@ fn pattern_context_for(
         ref_token,
         record_pat: None,
         impl_: fetch_immediate_impl(sema, original_file, pat.syntax()),
+        missing_variants,
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
index a654a5db574..82a1c10c531 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
@@ -411,3 +411,15 @@ fn main() {
         expect!["ty: i32, name: ?"],
     );
 }
+
+#[test]
+fn expected_type_ref_return_pos() {
+    check_expected_type_and_name(
+        r#"
+fn f(thing: u32) -> &u32 {
+    &thin$0
+}
+"#,
+        expect!["ty: u32, name: ?"],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
index 21b4bc2174b..9225c91bebf 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
@@ -37,7 +37,9 @@ pub(crate) fn render_struct_pat(
     let lookup = format_literal_lookup(name.as_str(), kind);
     let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?;
 
-    Some(build_completion(ctx, label, lookup, pat, strukt))
+    let db = ctx.db();
+
+    Some(build_completion(ctx, label, lookup, pat, strukt, strukt.ty(db), false))
 }
 
 pub(crate) fn render_variant_pat(
@@ -52,6 +54,7 @@ pub(crate) fn render_variant_pat(
 
     let fields = variant.fields(ctx.db());
     let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?;
+    let enum_ty = variant.parent_enum(ctx.db()).ty(ctx.db());
 
     let (name, escaped_name) = match path {
         Some(path) => (path.unescaped().to_string().into(), path.to_string().into()),
@@ -81,7 +84,15 @@ pub(crate) fn render_variant_pat(
         }
     };
 
-    Some(build_completion(ctx, label, lookup, pat, variant))
+    Some(build_completion(
+        ctx,
+        label,
+        lookup,
+        pat,
+        variant,
+        enum_ty,
+        pattern_ctx.missing_variants.contains(&variant),
+    ))
 }
 
 fn build_completion(
@@ -90,13 +101,22 @@ fn build_completion(
     lookup: SmolStr,
     pat: String,
     def: impl HasAttrs + Copy,
+    adt_ty: hir::Type,
+    // Missing in context of match statement completions
+    is_variant_missing: bool,
 ) -> CompletionItem {
+    let mut relevance = ctx.completion_relevance();
+
+    if is_variant_missing {
+        relevance.type_match = super::compute_type_match(ctx.completion, &adt_ty);
+    }
+
     let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label);
     item.set_documentation(ctx.docs(def))
         .set_deprecated(ctx.is_deprecated(def))
         .detail(&pat)
         .lookup_by(lookup)
-        .set_relevance(ctx.completion_relevance());
+        .set_relevance(relevance);
     match ctx.snippet_cap() {
         Some(snippet_cap) => item.insert_snippet(snippet_cap, pat),
         None => item.insert_text(pat),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
index ad9254e7f2e..c0e485c36fd 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
@@ -614,6 +614,7 @@ fn f(u: U) {
 
     check_empty(
         r#"
+#![rustc_coherence_is_core]
 #[lang = "u32"]
 impl u32 {
     pub const MIN: Self = 0;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
index 328faaa060f..65cefdb0856 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
@@ -47,6 +47,66 @@ fn foo(s: Struct) {
 }
 
 #[test]
+fn record_pattern_field_enum() {
+    check(
+        r#"
+//- minicore:result
+enum Baz { Foo, Bar }
+
+fn foo(baz: Baz) {
+    match baz {
+        Baz::Foo => (),
+        $0
+    }
+}
+"#,
+        expect![[r#"
+            en Baz
+            en Result
+            md core
+            ev Err
+            ev Ok
+            bn Baz::Bar Baz::Bar$0
+            bn Baz::Foo Baz::Foo$0
+            bn Err(…)   Err($1)$0
+            bn Ok(…)    Ok($1)$0
+            kw mut
+            kw ref
+        "#]],
+    );
+
+    check(
+        r#"
+//- minicore:result
+enum Baz { Foo, Bar }
+
+fn foo(baz: Baz) {
+    use Baz::*;
+    match baz {
+        Foo => (),
+        $0
+    }
+}
+ "#,
+        expect![[r#"
+         en Baz
+         en Result
+         md core
+         ev Bar
+         ev Err
+         ev Foo
+         ev Ok
+         bn Bar    Bar$0
+         bn Err(…) Err($1)$0
+         bn Foo    Foo$0
+         bn Ok(…)  Ok($1)$0
+         kw mut
+         kw ref
+         "#]],
+    );
+}
+
+#[test]
 fn pattern_enum_variant() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
index cb71c7b2bde..f8a6f6cd3ed 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
@@ -608,6 +608,7 @@ fn f() {
 }
 
 //- /core.rs crate:core
+#![rustc_coherence_is_core]
 #[lang = "u8"]
 impl u8 {
     pub const MAX: Self = 255;
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
index 244e99fe2e2..ea1d9cc4919 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
@@ -71,7 +71,7 @@ impl RootDatabase {
             base_db::SourceRootQuery
             base_db::SourceRootCratesQuery
 
-            // AstDatabase
+            // ExpandDatabase
             hir::db::AstIdMapQuery
             hir::db::ParseMacroExpansionQuery
             hir::db::InternMacroCallQuery
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index 1322f5228e8..4071c490b7f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -327,7 +327,7 @@ impl NameClass {
             let pat_parent = ident_pat.syntax().parent();
             if let Some(record_pat_field) = pat_parent.and_then(ast::RecordPatField::cast) {
                 if record_pat_field.name_ref().is_none() {
-                    if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
+                    if let Some((field, _)) = sema.resolve_record_pat_field(&record_pat_field) {
                         return Some(NameClass::PatFieldShorthand {
                             local_def: local,
                             field_ref: field,
@@ -483,6 +483,13 @@ impl NameRefClass {
                 },
                 ast::RecordPatField(record_pat_field) => {
                     sema.resolve_record_pat_field(&record_pat_field)
+                        .map(|(field, ..)|field)
+                        .map(Definition::Field)
+                        .map(NameRefClass::Definition)
+                },
+                ast::RecordExprField(record_expr_field) => {
+                    sema.resolve_record_field(&record_expr_field)
+                        .map(|(field, ..)|field)
                         .map(Definition::Field)
                         .map(NameRefClass::Definition)
                 },
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
index ae120470047..b1df11bf911 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
@@ -50,7 +50,7 @@ use base_db::{
     AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast,
 };
 use hir::{
-    db::{AstDatabase, DefDatabase, HirDatabase},
+    db::{DefDatabase, ExpandDatabase, HirDatabase},
     symbols::FileSymbolKind,
 };
 use stdx::hash::NoHashHashSet;
@@ -68,7 +68,7 @@ pub type FxIndexMap<K, V> =
 #[salsa::database(
     base_db::SourceDatabaseExtStorage,
     base_db::SourceDatabaseStorage,
-    hir::db::AstDatabaseStorage,
+    hir::db::ExpandDatabaseStorage,
     hir::db::DefDatabaseStorage,
     hir::db::HirDatabaseStorage,
     hir::db::InternDatabaseStorage,
@@ -95,8 +95,8 @@ impl fmt::Debug for RootDatabase {
     }
 }
 
-impl Upcast<dyn AstDatabase> for RootDatabase {
-    fn upcast(&self) -> &(dyn AstDatabase + 'static) {
+impl Upcast<dyn ExpandDatabase> for RootDatabase {
+    fn upcast(&self) -> &(dyn ExpandDatabase + 'static) {
         &*self
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
new file mode 100644
index 00000000000..72af9ebfcbb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
@@ -0,0 +1,77 @@
+use hir::InFile;
+
+use crate::{Diagnostic, DiagnosticsContext, Severity};
+
+// Diagnostic: incoherent-impl
+//
+// This diagnostic is triggered if the targe type of an impl is from a foreign crate.
+pub(crate) fn incoherent_impl(ctx: &DiagnosticsContext<'_>, d: &hir::IncoherentImpl) -> Diagnostic {
+    Diagnostic::new(
+        "incoherent-impl",
+        format!("cannot define inherent `impl` for foreign type"),
+        ctx.sema.diagnostics_display_range(InFile::new(d.file_id, d.impl_.clone().into())).range,
+    )
+    .severity(Severity::Error)
+}
+
+#[cfg(test)]
+mod change_case {
+    use crate::tests::check_diagnostics;
+
+    #[test]
+    fn primitive() {
+        check_diagnostics(
+            r#"
+  impl bool {}
+//^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type
+"#,
+        );
+    }
+
+    #[test]
+    fn primitive_rustc_allow_incoherent_impl() {
+        check_diagnostics(
+            r#"
+impl bool {
+    #[rustc_allow_incoherent_impl]
+    fn falsch(self) -> Self { false }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn rustc_allow_incoherent_impl() {
+        check_diagnostics(
+            r#"
+//- /lib.rs crate:foo
+#[rustc_has_incoherent_inherent_impls]
+pub struct S;
+//- /main.rs crate:main deps:foo
+impl foo::S {
+    #[rustc_allow_incoherent_impl]
+    fn func(self) {}
+}
+"#,
+        );
+        check_diagnostics(
+            r#"
+//- /lib.rs crate:foo
+pub struct S;
+//- /main.rs crate:main deps:foo
+  impl foo::S { #[rustc_allow_incoherent_impl] fn func(self) {} }
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type
+"#,
+        );
+        check_diagnostics(
+            r#"
+//- /lib.rs crate:foo
+#[rustc_has_incoherent_inherent_impls]
+pub struct S;
+//- /main.rs crate:main deps:foo
+  impl foo::S { fn func(self) {} }
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index 6a78c08d44c..db88bf7b931 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -1,4 +1,4 @@
-use hir::{db::AstDatabase, InFile};
+use hir::{db::ExpandDatabase, InFile};
 use ide_db::{assists::Assist, defs::NameClass};
 use syntax::AstNode;
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 14039087b3f..5c4327ff934 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -1,6 +1,6 @@
 use either::Either;
 use hir::{
-    db::{AstDatabase, HirDatabase},
+    db::{ExpandDatabase, HirDatabase},
     known, AssocItem, HirDisplay, InFile, Type,
 };
 use ide_db::{
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index ea1ea5a216d..eb32db25065 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -1,4 +1,10 @@
-use crate::{Diagnostic, DiagnosticsContext};
+use hir::db::ExpandDatabase;
+use ide_db::{assists::Assist, source_change::SourceChange};
+use syntax::{ast, SyntaxNode};
+use syntax::{match_ast, AstNode};
+use text_edit::TextEdit;
+
+use crate::{fix, Diagnostic, DiagnosticsContext};
 
 // Diagnostic: missing-unsafe
 //
@@ -9,11 +15,83 @@ pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf
         "this operation is unsafe and requires an unsafe function or block",
         ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
     )
+    .with_fixes(fixes(ctx, d))
+}
+
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option<Vec<Assist>> {
+    // The fixit will not work correctly for macro expansions, so we don't offer it in that case.
+    if d.expr.file_id.is_macro() {
+        return None;
+    }
+
+    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
+    let expr = d.expr.value.to_node(&root);
+
+    let node_to_add_unsafe_block = pick_best_node_to_add_unsafe_block(&expr)?;
+
+    let replacement = format!("unsafe {{ {} }}", node_to_add_unsafe_block.text());
+    let edit = TextEdit::replace(node_to_add_unsafe_block.text_range(), replacement);
+    let source_change =
+        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
+    Some(vec![fix("add_unsafe", "Add unsafe block", source_change, expr.syntax().text_range())])
+}
+
+// Pick the first ancestor expression of the unsafe `expr` that is not a
+// receiver of a method call, a field access, the left-hand side of an
+// assignment, or a reference. As all of those cases would incur a forced move
+// if wrapped which might not be wanted. That is:
+// - `unsafe_expr.foo` -> `unsafe { unsafe_expr.foo }`
+// - `unsafe_expr.foo.bar` -> `unsafe { unsafe_expr.foo.bar }`
+// - `unsafe_expr.foo()` -> `unsafe { unsafe_expr.foo() }`
+// - `unsafe_expr.foo.bar()` -> `unsafe { unsafe_expr.foo.bar() }`
+// - `unsafe_expr += 1` -> `unsafe { unsafe_expr += 1 }`
+// - `&unsafe_expr` -> `unsafe { &unsafe_expr }`
+// - `&&unsafe_expr` -> `unsafe { &&unsafe_expr }`
+fn pick_best_node_to_add_unsafe_block(unsafe_expr: &ast::Expr) -> Option<SyntaxNode> {
+    // The `unsafe_expr` might be:
+    // - `ast::CallExpr`: call an unsafe function
+    // - `ast::MethodCallExpr`: call an unsafe method
+    // - `ast::PrefixExpr`: dereference a raw pointer
+    // - `ast::PathExpr`: access a static mut variable
+    for (node, parent) in
+        unsafe_expr.syntax().ancestors().zip(unsafe_expr.syntax().ancestors().skip(1))
+    {
+        match_ast! {
+            match parent {
+                // If the `parent` is a `MethodCallExpr`, that means the `node`
+                // is the receiver of the method call, because only the receiver
+                // can be a direct child of a method call. The method name
+                // itself is not an expression but a `NameRef`, and an argument
+                // is a direct child of an `ArgList`.
+                ast::MethodCallExpr(_) => continue,
+                ast::FieldExpr(_) => continue,
+                ast::RefExpr(_) => continue,
+                ast::BinExpr(it) => {
+                    // Check if the `node` is the left-hand side of an
+                    // assignment, if so, we don't want to wrap it in an unsafe
+                    // block, e.g. `unsafe_expr += 1`
+                    let is_left_hand_side_of_assignment = {
+                        if let Some(ast::BinaryOp::Assignment { .. }) = it.op_kind() {
+                            it.lhs().map(|lhs| lhs.syntax().text_range().contains_range(node.text_range())).unwrap_or(false)
+                        } else {
+                            false
+                        }
+                    };
+                    if !is_left_hand_side_of_assignment {
+                        return Some(node);
+                    }
+                },
+                _ => { return Some(node); }
+
+            }
+        }
+    }
+    None
 }
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::check_diagnostics;
+    use crate::tests::{check_diagnostics, check_fix, check_no_fix};
 
     #[test]
     fn missing_unsafe_diagnostic_with_raw_ptr() {
@@ -23,7 +101,7 @@ fn main() {
     let x = &5 as *const usize;
     unsafe { let y = *x; }
     let z = *x;
-}         //^^ error: this operation is unsafe and requires an unsafe function or block
+}         //^^💡 error: this operation is unsafe and requires an unsafe function or block
 "#,
         )
     }
@@ -48,9 +126,9 @@ unsafe fn unsafe_fn() {
 
 fn main() {
     unsafe_fn();
-  //^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
+  //^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block
     HasUnsafe.unsafe_fn();
-  //^^^^^^^^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
+  //^^^^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block
     unsafe {
         unsafe_fn();
         HasUnsafe.unsafe_fn();
@@ -72,7 +150,7 @@ static mut STATIC_MUT: Ty = Ty { a: 0 };
 
 fn main() {
     let x = STATIC_MUT.a;
-          //^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
+          //^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block
     unsafe {
         let x = STATIC_MUT.a;
     }
@@ -94,9 +172,298 @@ extern "rust-intrinsic" {
 fn main() {
     let _ = bitreverse(12);
     let _ = floorf32(12.0);
-          //^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
+          //^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block
 }
 "#,
         );
     }
+
+    #[test]
+    fn add_unsafe_block_when_dereferencing_a_raw_pointer() {
+        check_fix(
+            r#"
+fn main() {
+    let x = &5 as *const usize;
+    let z = *x$0;
+}
+"#,
+            r#"
+fn main() {
+    let x = &5 as *const usize;
+    let z = unsafe { *x };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn add_unsafe_block_when_calling_unsafe_function() {
+        check_fix(
+            r#"
+unsafe fn func() {
+    let x = &5 as *const usize;
+    let z = *x;
+}
+fn main() {
+    func$0();
+}
+"#,
+            r#"
+unsafe fn func() {
+    let x = &5 as *const usize;
+    let z = *x;
+}
+fn main() {
+    unsafe { func() };
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn add_unsafe_block_when_calling_unsafe_method() {
+        check_fix(
+            r#"
+struct S(usize);
+impl S {
+    unsafe fn func(&self) {
+        let x = &self.0 as *const usize;
+        let z = *x;
+    }
+}
+fn main() {
+    let s = S(5);
+    s.func$0();
+}
+"#,
+            r#"
+struct S(usize);
+impl S {
+    unsafe fn func(&self) {
+        let x = &self.0 as *const usize;
+        let z = *x;
+    }
+}
+fn main() {
+    let s = S(5);
+    unsafe { s.func() };
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn add_unsafe_block_when_accessing_mutable_static() {
+        check_fix(
+            r#"
+struct Ty {
+    a: u8,
+}
+
+static mut STATIC_MUT: Ty = Ty { a: 0 };
+
+fn main() {
+    let x = STATIC_MUT$0.a;
+}
+"#,
+            r#"
+struct Ty {
+    a: u8,
+}
+
+static mut STATIC_MUT: Ty = Ty { a: 0 };
+
+fn main() {
+    let x = unsafe { STATIC_MUT.a };
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn add_unsafe_block_when_calling_unsafe_intrinsic() {
+        check_fix(
+            r#"
+extern "rust-intrinsic" {
+    pub fn floorf32(x: f32) -> f32;
+}
+
+fn main() {
+    let _ = floorf32$0(12.0);
+}
+"#,
+            r#"
+extern "rust-intrinsic" {
+    pub fn floorf32(x: f32) -> f32;
+}
+
+fn main() {
+    let _ = unsafe { floorf32(12.0) };
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn unsafe_expr_as_a_receiver_of_a_method_call() {
+        check_fix(
+            r#"
+unsafe fn foo() -> String {
+    "string".to_string()
+}
+
+fn main() {
+    foo$0().len();
+}
+"#,
+            r#"
+unsafe fn foo() -> String {
+    "string".to_string()
+}
+
+fn main() {
+    unsafe { foo().len() };
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn unsafe_expr_as_an_argument_of_a_method_call() {
+        check_fix(
+            r#"
+static mut STATIC_MUT: u8 = 0;
+
+fn main() {
+    let mut v = vec![];
+    v.push(STATIC_MUT$0);
+}
+"#,
+            r#"
+static mut STATIC_MUT: u8 = 0;
+
+fn main() {
+    let mut v = vec![];
+    v.push(unsafe { STATIC_MUT });
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn unsafe_expr_as_left_hand_side_of_assignment() {
+        check_fix(
+            r#"
+static mut STATIC_MUT: u8 = 0;
+
+fn main() {
+    STATIC_MUT$0 = 1;
+}
+"#,
+            r#"
+static mut STATIC_MUT: u8 = 0;
+
+fn main() {
+    unsafe { STATIC_MUT = 1 };
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn unsafe_expr_as_right_hand_side_of_assignment() {
+        check_fix(
+            r#"
+static mut STATIC_MUT: u8 = 0;
+
+fn main() {
+    let x;
+    x = STATIC_MUT$0;
+}
+"#,
+            r#"
+static mut STATIC_MUT: u8 = 0;
+
+fn main() {
+    let x;
+    x = unsafe { STATIC_MUT };
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn unsafe_expr_in_binary_plus() {
+        check_fix(
+            r#"
+static mut STATIC_MUT: u8 = 0;
+
+fn main() {
+    let x = STATIC_MUT$0 + 1;
+}
+"#,
+            r#"
+static mut STATIC_MUT: u8 = 0;
+
+fn main() {
+    let x = unsafe { STATIC_MUT } + 1;
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn ref_to_unsafe_expr() {
+        check_fix(
+            r#"
+static mut STATIC_MUT: u8 = 0;
+
+fn main() {
+    let x = &STATIC_MUT$0;
+}
+"#,
+            r#"
+static mut STATIC_MUT: u8 = 0;
+
+fn main() {
+    let x = unsafe { &STATIC_MUT };
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn ref_ref_to_unsafe_expr() {
+        check_fix(
+            r#"
+static mut STATIC_MUT: u8 = 0;
+
+fn main() {
+    let x = &&STATIC_MUT$0;
+}
+"#,
+            r#"
+static mut STATIC_MUT: u8 = 0;
+
+fn main() {
+    let x = unsafe { &&STATIC_MUT };
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn unsafe_expr_in_macro_call() {
+        check_no_fix(
+            r#"
+unsafe fn foo() -> u8 {
+    0
+}
+
+fn main() {
+    let x = format!("foo: {}", foo$0());
+}
+            "#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 84189a5d560..96470265d11 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -506,6 +506,30 @@ fn main() {
     }
 
     #[test]
+    fn initialization_is_not_mutation_in_loop() {
+        check_diagnostics(
+            r#"
+fn main() {
+    let a;
+    loop {
+        let c @ (
+            mut b,
+          //^^^^^ 💡 weak: variable does not need to be mutable
+            mut d
+          //^^^^^ 💡 weak: variable does not need to be mutable
+        );
+        a = 1;
+      //^^^^^ 💡 error: cannot mutate immutable variable `a`
+        b = 1;
+        c = (2, 3);
+        d = 3;
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn function_arguments_are_initialized() {
         check_diagnostics(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index 8da04e628d6..24c521ed1a8 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -1,4 +1,4 @@
-use hir::{db::AstDatabase, HasSource, HirDisplay, Semantics};
+use hir::{db::ExpandDatabase, HasSource, HirDisplay, Semantics};
 use ide_db::{base_db::FileId, source_change::SourceChange, RootDatabase};
 use syntax::{
     ast::{self, edit::IndentLevel, make},
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
index e630ae36866..be83ad6aaad 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
@@ -65,4 +65,24 @@ fn main(s: module::Struct) {
 "#,
         );
     }
+
+    #[test]
+    fn block_module_madness() {
+        check_diagnostics(
+            r#"
+fn main() {
+    let strukt = {
+        use crate as ForceParentBlockDefMap;
+        {
+            pub struct Struct {
+                field: (),
+            }
+            Struct { field: () }
+        }
+    };
+    strukt.field;
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index a0c276cc332..9b1c65983e6 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -1,4 +1,4 @@
-use hir::{db::AstDatabase, InFile};
+use hir::{db::ExpandDatabase, InFile};
 use ide_db::source_change::SourceChange;
 use syntax::{
     ast::{self, HasArgList},
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index b57a13e53e6..4abc25a28fb 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -1,5 +1,5 @@
 use either::Either;
-use hir::{db::AstDatabase, HirDisplay, InFile, Type};
+use hir::{db::ExpandDatabase, HirDisplay, InFile, Type};
 use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
 use syntax::{
     ast::{self, BlockExpr, ExprStmt},
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 7de03416e56..cefa74e523e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -1,4 +1,4 @@
-use hir::{db::AstDatabase, HirDisplay, InFile};
+use hir::{db::ExpandDatabase, HirDisplay, InFile};
 use ide_db::{
     assists::{Assist, AssistId, AssistKind},
     base_db::FileRange,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 4b0e64cb896..f3ec6efa752 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -1,4 +1,4 @@
-use hir::{db::AstDatabase, HirDisplay};
+use hir::{db::ExpandDatabase, HirDisplay};
 use ide_db::{
     assists::{Assist, AssistId, AssistKind},
     base_db::FileRange,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
index 91395f1d841..94614f11c33 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
@@ -1,4 +1,4 @@
-use hir::db::AstDatabase;
+use hir::db::ExpandDatabase;
 use ide_db::{assists::Assist, base_db::AnchoredPathBuf, source_change::FileSystemEdit};
 use itertools::Itertools;
 use syntax::AstNode;
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index f6c9b79c30c..71f136b8c90 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -29,6 +29,7 @@ mod handlers {
     pub(crate) mod break_outside_of_loop;
     pub(crate) mod expected_function;
     pub(crate) mod inactive_code;
+    pub(crate) mod incoherent_impl;
     pub(crate) mod incorrect_case;
     pub(crate) mod invalid_derive_target;
     pub(crate) mod macro_error;
@@ -254,6 +255,7 @@ pub fn diagnostics(
             AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
             AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d),
             AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d),
+            AnyDiagnostic::IncoherentImpl(d) => handlers::incoherent_impl::incoherent_impl(&ctx, &d),
             AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
             AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
             AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
index 190ab80ba0f..a1a119629a9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
@@ -297,6 +297,7 @@ impl Foo<str> {}
 //- /lib.rs crate:main deps:core
 fn foo(_: bool$0) {{}}
 //- /libcore.rs crate:core
+#![rustc_coherence_is_core]
 #[lang = "bool"]
 impl bool {}
    //^^^^
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
index 55cdb3200ea..6d2d0bd6351 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
@@ -55,7 +55,7 @@ pub(crate) fn goto_type_definition(
                                 ty
                             } else {
                                 let record_field = ast::RecordPatField::for_field_name_ref(&it)?;
-                                sema.resolve_record_pat_field(&record_field)?.ty(db)
+                                sema.resolve_record_pat_field(&record_field)?.1
                             }
                         },
                         _ => return None,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
index 729780fa0c9..46505b30441 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
@@ -31,19 +31,31 @@ pub(super) fn hints(
         return None;
     }
 
-    // These inherit from the inner expression which would result in duplicate hints
-    if let ast::Expr::ParenExpr(_)
-    | ast::Expr::IfExpr(_)
-    | ast::Expr::BlockExpr(_)
-    | ast::Expr::MatchExpr(_) = expr
-    {
+    // ParenExpr resolve to their contained expressions HIR so they will dupe these hints
+    if let ast::Expr::ParenExpr(_) = expr {
         return None;
     }
+    if let ast::Expr::BlockExpr(b) = expr {
+        if !b.is_standalone() {
+            return None;
+        }
+    }
 
     let descended = sema.descend_node_into_attributes(expr.clone()).pop();
     let desc_expr = descended.as_ref().unwrap_or(expr);
     let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
 
+    if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr {
+        if let [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), source: _, target }] =
+            &*adjustments
+        {
+            // Don't show unnecessary reborrows for these, they will just repeat the inner ones again
+            if source == target {
+                return None;
+            }
+        }
+    }
+
     let (postfix, needs_outer_parens, needs_inner_parens) =
         mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode);
 
@@ -67,6 +79,7 @@ pub(super) fn hints(
 
     for Adjustment { source, target, kind } in iter {
         if source == target {
+            cov_mark::hit!(same_type_adjustment);
             continue;
         }
 
@@ -251,7 +264,7 @@ mod tests {
         check_with_config(
             InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
             r#"
-//- minicore: coerce_unsized, fn
+//- minicore: coerce_unsized, fn, eq
 fn main() {
     let _: u32         = loop {};
                        //^^^^^^^<never-to-any>
@@ -332,7 +345,7 @@ fn main() {
         loop {}
       //^^^^^^^<never-to-any>
     };
-    let _: &mut [u32] = match () { () => &mut [] }
+    let _: &mut [u32] = match () { () => &mut [] };
                                        //^^^^^^^<unsize>
                                        //^^^^^^^&mut $
                                        //^^^^^^^*
@@ -341,6 +354,12 @@ fn main() {
                          //^^^^^^^^^^<unsize>
                          //^^^^^^^^^^&mut $
                          //^^^^^^^^^^*
+    () == ();
+ // ^^&
+       // ^^&
+    (()) == {()};
+  // ^^&
+         // ^^^^&
 }
 
 #[derive(Copy, Clone)]
@@ -363,7 +382,7 @@ impl Struct {
                 ..DISABLED_CONFIG
             },
             r#"
-//- minicore: coerce_unsized, fn
+//- minicore: coerce_unsized, fn, eq
 fn main() {
 
     Struct.consume();
@@ -419,7 +438,7 @@ fn main() {
         loop {}
       //^^^^^^^.<never-to-any>
     };
-    let _: &mut [u32] = match () { () => &mut [] }
+    let _: &mut [u32] = match () { () => &mut [] };
                                        //^^^^^^^(
                                        //^^^^^^^)
                                        //^^^^^^^.*
@@ -432,6 +451,12 @@ fn main() {
                          //^^^^^^^^^^.*
                          //^^^^^^^^^^.&mut
                          //^^^^^^^^^^.<unsize>
+    () == ();
+ // ^^.&
+       // ^^.&
+    (()) == {()};
+  // ^^.&
+         // ^^^^.&
 }
 
 #[derive(Copy, Clone)]
@@ -499,6 +524,7 @@ fn main() {
 
     #[test]
     fn never_to_never_is_never_shown() {
+        cov_mark::check!(same_type_adjustment);
         check_with_config(
             InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index 0a7513e465a..1e1771259b1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -435,7 +435,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 3386..3394,
+                                        range: 3415..3423,
                                     },
                                 ),
                                 tooltip: "",
@@ -448,7 +448,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 3418..3422,
+                                        range: 3447..3451,
                                     },
                                 ),
                                 tooltip: "",
@@ -468,7 +468,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 3386..3394,
+                                        range: 3415..3423,
                                     },
                                 ),
                                 tooltip: "",
@@ -481,7 +481,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 3418..3422,
+                                        range: 3447..3451,
                                     },
                                 ),
                                 tooltip: "",
@@ -501,7 +501,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 3386..3394,
+                                        range: 3415..3423,
                                     },
                                 ),
                                 tooltip: "",
@@ -514,7 +514,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 3418..3422,
+                                        range: 3447..3451,
                                     },
                                 ),
                                 tooltip: "",
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index 2c08c457b33..4b2c139f6f4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -16,7 +16,7 @@ use stdx::format_to;
 use syntax::{
     algo,
     ast::{self, HasArgList},
-    match_ast, AstNode, Direction, SyntaxToken, TextRange, TextSize,
+    match_ast, AstNode, Direction, SyntaxElementChildren, SyntaxToken, TextRange, TextSize,
 };
 
 use crate::RootDatabase;
@@ -102,6 +102,20 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio
                     }
                     return signature_help_for_record_lit(&sema, record, token);
                 },
+                ast::RecordPat(record) => {
+                    let cursor_outside = record.record_pat_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token);
+                    if cursor_outside {
+                        continue;
+                    }
+                    return signature_help_for_record_pat(&sema, record, token);
+                },
+                ast::TupleStructPat(tuple_pat) => {
+                    let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token);
+                    if cursor_outside {
+                        continue;
+                    }
+                    return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token);
+                },
                 _ => (),
             }
         }
@@ -346,11 +360,112 @@ fn signature_help_for_record_lit(
     record: ast::RecordExpr,
     token: SyntaxToken,
 ) -> Option<SignatureHelp> {
-    let active_parameter = record
-        .record_expr_field_list()?
+    signature_help_for_record_(
+        sema,
+        record.record_expr_field_list()?.syntax().children_with_tokens(),
+        &record.path()?,
+        record
+            .record_expr_field_list()?
+            .fields()
+            .filter_map(|field| sema.resolve_record_field(&field))
+            .map(|(field, _, ty)| (field, ty)),
+        token,
+    )
+}
+
+fn signature_help_for_record_pat(
+    sema: &Semantics<'_, RootDatabase>,
+    record: ast::RecordPat,
+    token: SyntaxToken,
+) -> Option<SignatureHelp> {
+    signature_help_for_record_(
+        sema,
+        record.record_pat_field_list()?.syntax().children_with_tokens(),
+        &record.path()?,
+        record
+            .record_pat_field_list()?
+            .fields()
+            .filter_map(|field| sema.resolve_record_pat_field(&field)),
+        token,
+    )
+}
+
+fn signature_help_for_tuple_struct_pat(
+    sema: &Semantics<'_, RootDatabase>,
+    pat: ast::TupleStructPat,
+    token: SyntaxToken,
+) -> Option<SignatureHelp> {
+    let rest_pat = pat.fields().find(|it| matches!(it, ast::Pat::RestPat(_)));
+    let is_left_of_rest_pat =
+        rest_pat.map_or(true, |it| token.text_range().start() < it.syntax().text_range().end());
+
+    let mut res = SignatureHelp {
+        doc: None,
+        signature: String::new(),
+        parameters: vec![],
+        active_parameter: None,
+    };
+
+    let db = sema.db;
+    let path_res = sema.resolve_path(&pat.path()?)?;
+    let fields: Vec<_> = if let PathResolution::Def(ModuleDef::Variant(variant)) = path_res {
+        let en = variant.parent_enum(db);
+
+        res.doc = en.docs(db).map(|it| it.into());
+        format_to!(res.signature, "enum {}::{} (", en.name(db), variant.name(db));
+        variant.fields(db)
+    } else {
+        let adt = match path_res {
+            PathResolution::SelfType(imp) => imp.self_ty(db).as_adt()?,
+            PathResolution::Def(ModuleDef::Adt(adt)) => adt,
+            _ => return None,
+        };
+
+        match adt {
+            hir::Adt::Struct(it) => {
+                res.doc = it.docs(db).map(|it| it.into());
+                format_to!(res.signature, "struct {} (", it.name(db));
+                it.fields(db)
+            }
+            _ => return None,
+        }
+    };
+    let commas = pat
         .syntax()
         .children_with_tokens()
         .filter_map(syntax::NodeOrToken::into_token)
+        .filter(|t| t.kind() == syntax::T![,]);
+    res.active_parameter = Some(if is_left_of_rest_pat {
+        commas.take_while(|t| t.text_range().start() <= token.text_range().start()).count()
+    } else {
+        let n_commas = commas
+            .collect::<Vec<_>>()
+            .into_iter()
+            .rev()
+            .take_while(|t| t.text_range().start() > token.text_range().start())
+            .count();
+        fields.len().saturating_sub(1).saturating_sub(n_commas)
+    });
+
+    let mut buf = String::new();
+    for ty in fields.into_iter().map(|it| it.ty(db)) {
+        format_to!(buf, "{}", ty.display_truncated(db, Some(20)));
+        res.push_call_param(&buf);
+        buf.clear();
+    }
+    res.signature.push_str(")");
+    Some(res)
+}
+
+fn signature_help_for_record_(
+    sema: &Semantics<'_, RootDatabase>,
+    field_list_children: SyntaxElementChildren,
+    path: &ast::Path,
+    fields2: impl Iterator<Item = (hir::Field, hir::Type)>,
+    token: SyntaxToken,
+) -> Option<SignatureHelp> {
+    let active_parameter = field_list_children
+        .filter_map(syntax::NodeOrToken::into_token)
         .filter(|t| t.kind() == syntax::T![,])
         .take_while(|t| t.text_range().start() <= token.text_range().start())
         .count();
@@ -365,7 +480,7 @@ fn signature_help_for_record_lit(
     let fields;
 
     let db = sema.db;
-    let path_res = sema.resolve_path(&record.path()?)?;
+    let path_res = sema.resolve_path(path)?;
     if let PathResolution::Def(ModuleDef::Variant(variant)) = path_res {
         fields = variant.fields(db);
         let en = variant.parent_enum(db);
@@ -397,8 +512,7 @@ fn signature_help_for_record_lit(
     let mut fields =
         fields.into_iter().map(|field| (field.name(db), Some(field))).collect::<FxIndexMap<_, _>>();
     let mut buf = String::new();
-    for field in record.record_expr_field_list()?.fields() {
-        let Some((field, _, ty)) = sema.resolve_record_field(&field) else { continue };
+    for (field, ty) in fields2 {
         let name = field.name(db);
         format_to!(buf, "{name}: {}", ty.display_truncated(db, Some(20)));
         res.push_record_field(&buf);
@@ -439,6 +553,7 @@ mod tests {
         (database, FilePosition { file_id, offset })
     }
 
+    #[track_caller]
     fn check(ra_fixture: &str, expect: Expect) {
         let fixture = format!(
             r#"
@@ -891,6 +1006,119 @@ fn main() {
     }
 
     #[test]
+    fn tuple_struct_pat() {
+        check(
+            r#"
+/// A cool tuple struct
+struct S(u32, i32);
+fn main() {
+    let S(0, $0);
+}
+"#,
+            expect![[r#"
+                A cool tuple struct
+                ------
+                struct S (u32, i32)
+                          ---  ^^^
+            "#]],
+        );
+    }
+
+    #[test]
+    fn tuple_struct_pat_rest() {
+        check(
+            r#"
+/// A cool tuple struct
+struct S(u32, i32, f32, u16);
+fn main() {
+    let S(0, .., $0);
+}
+"#,
+            expect![[r#"
+                A cool tuple struct
+                ------
+                struct S (u32, i32, f32, u16)
+                          ---  ---  ---  ^^^
+            "#]],
+        );
+        check(
+            r#"
+/// A cool tuple struct
+struct S(u32, i32, f32, u16, u8);
+fn main() {
+    let S(0, .., $0, 0);
+}
+"#,
+            expect![[r#"
+                A cool tuple struct
+                ------
+                struct S (u32, i32, f32, u16, u8)
+                          ---  ---  ---  ^^^  --
+            "#]],
+        );
+        check(
+            r#"
+/// A cool tuple struct
+struct S(u32, i32, f32, u16);
+fn main() {
+    let S($0, .., 1);
+}
+"#,
+            expect![[r#"
+                A cool tuple struct
+                ------
+                struct S (u32, i32, f32, u16)
+                          ^^^  ---  ---  ---
+            "#]],
+        );
+        check(
+            r#"
+/// A cool tuple struct
+struct S(u32, i32, f32, u16, u8);
+fn main() {
+    let S(1, .., 1, $0, 2);
+}
+"#,
+            expect![[r#"
+                A cool tuple struct
+                ------
+                struct S (u32, i32, f32, u16, u8)
+                          ---  ---  ---  ^^^  --
+            "#]],
+        );
+        check(
+            r#"
+/// A cool tuple struct
+struct S(u32, i32, f32, u16);
+fn main() {
+    let S(1, $0.., 1);
+}
+"#,
+            expect![[r#"
+                A cool tuple struct
+                ------
+                struct S (u32, i32, f32, u16)
+                          ---  ^^^  ---  ---
+            "#]],
+        );
+        check(
+            r#"
+/// A cool tuple struct
+struct S(u32, i32, f32, u16);
+fn main() {
+    let S(1, ..$0, 1);
+}
+"#,
+            expect![[r#"
+                A cool tuple struct
+                ------
+                struct S (u32, i32, f32, u16)
+                          ---  ^^^  ---  ---
+            "#]],
+        );
+    }
+
+    #[test]
     fn generic_struct() {
         check(
             r#"
@@ -1551,6 +1779,29 @@ impl S {
     }
 
     #[test]
+    fn record_pat() {
+        check(
+            r#"
+struct Strukt<T, U = ()> {
+    t: T,
+    u: U,
+    unit: (),
+}
+fn f() {
+    let Strukt {
+        u: 0,
+        $0
+    }
+}
+"#,
+            expect![[r#"
+                struct Strukt { u: i32, t: T, unit: () }
+                                ------  ^^^^  --------
+            "#]],
+        );
+    }
+
+    #[test]
     fn test_enum_in_nested_method_in_lambda() {
         check(
             r#"
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
index abcefffa23f..5f4977886f6 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
@@ -431,14 +431,15 @@ fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker {
 
 fn pat_list(p: &mut Parser<'_>, ket: SyntaxKind) {
     while !p.at(EOF) && !p.at(ket) {
-        if !p.at_ts(PAT_TOP_FIRST) {
-            p.error("expected a pattern");
-            break;
-        }
-
         pattern_top(p);
-        if !p.at(ket) {
-            p.expect(T![,]);
+        if !p.at(T![,]) {
+            if p.at_ts(PAT_TOP_FIRST) {
+                p.error(format!("expected {:?}, got {:?}", T![,], p.current()));
+            } else {
+                break;
+            }
+        } else {
+            p.bump(T![,]);
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
index 6df1273edd6..4e5d640f175 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
@@ -429,8 +429,9 @@ impl WorkspaceBuildScripts {
             for p in rustc.packages() {
                 let package = &rustc[p];
                 if package.targets.iter().any(|&it| rustc[it].is_proc_macro) {
-                    if let Some((_, path)) =
-                        proc_macro_dylibs.iter().find(|(name, _)| *name == package.name)
+                    if let Some((_, path)) = proc_macro_dylibs
+                        .iter()
+                        .find(|(name, _)| *name.trim_start_matches("lib") == package.name)
                     {
                         bs.outputs[p].proc_macro_dylib_path = Some(path.clone());
                     }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index 732adc50b50..01162b1a8ba 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -50,7 +50,7 @@ impl ops::Index<Target> for CargoWorkspace {
 
 /// Describes how to set the rustc source directory.
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub enum RustcSource {
+pub enum RustLibSource {
     /// Explicit path for the rustc source directory.
     Path(AbsPathBuf),
     /// Try to automatically detect where the rustc source directory is.
@@ -95,10 +95,10 @@ pub struct CargoConfig {
     /// rustc target
     pub target: Option<String>,
     /// Sysroot loading behavior
-    pub sysroot: Option<RustcSource>,
+    pub sysroot: Option<RustLibSource>,
     pub sysroot_src: Option<AbsPathBuf>,
     /// rustc private crate source
-    pub rustc_source: Option<RustcSource>,
+    pub rustc_source: Option<RustLibSource>,
     /// crates to disable `#[cfg(test)]` on
     pub unset_test_crates: UnsetTestCrates,
     /// Invoke `cargo check` through the RUSTC_WRAPPER.
diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
index 9b6a71db811..70cb71ae3bd 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
@@ -44,7 +44,7 @@ pub use crate::{
     build_scripts::WorkspaceBuildScripts,
     cargo_workspace::{
         CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency,
-        RustcSource, Target, TargetData, TargetKind, UnsetTestCrates,
+        RustLibSource, Target, TargetData, TargetKind, UnsetTestCrates,
     },
     manifest_path::ManifestPath,
     project_json::{ProjectJson, ProjectJsonData},
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index 749eee531ee..3754accbb03 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -24,8 +24,8 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGr
     let project_workspace = ProjectWorkspace::Cargo {
         cargo: cargo_workspace,
         build_scripts: WorkspaceBuildScripts::default(),
-        sysroot: None,
-        rustc: None,
+        sysroot: Err(None),
+        rustc: Err(None),
         rustc_cfg: Vec::new(),
         cfg_overrides,
         toolchain: None,
@@ -37,7 +37,7 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGr
 fn load_rust_project(file: &str) -> CrateGraph {
     let data = get_test_json_file(file);
     let project = rooted_project_json(data);
-    let sysroot = Some(get_fake_sysroot());
+    let sysroot = Ok(get_fake_sysroot());
     let project_workspace = ProjectWorkspace::Json { project, sysroot, rustc_cfg: Vec::new() };
     to_crate_graph(project_workspace)
 }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index faa6816fdc2..d1e53e12eeb 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -17,7 +17,7 @@ use stdx::{always, hash::NoHashHashMap};
 
 use crate::{
     build_scripts::BuildScriptOutput,
-    cargo_workspace::{DepKind, PackageData, RustcSource},
+    cargo_workspace::{DepKind, PackageData, RustLibSource},
     cfg_flag::CfgFlag,
     rustc_cfg,
     sysroot::SysrootCrate,
@@ -69,8 +69,8 @@ pub enum ProjectWorkspace {
     Cargo {
         cargo: CargoWorkspace,
         build_scripts: WorkspaceBuildScripts,
-        sysroot: Option<Sysroot>,
-        rustc: Option<(CargoWorkspace, WorkspaceBuildScripts)>,
+        sysroot: Result<Sysroot, Option<String>>,
+        rustc: Result<(CargoWorkspace, WorkspaceBuildScripts), Option<String>>,
         /// Holds cfg flags for the current target. We get those by running
         /// `rustc --print cfg`.
         ///
@@ -82,7 +82,7 @@ pub enum ProjectWorkspace {
         target_layout: Result<String, String>,
     },
     /// Project workspace was manually specified using a `rust-project.json` file.
-    Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
+    Json { project: ProjectJson, sysroot: Result<Sysroot, Option<String>>, rustc_cfg: Vec<CfgFlag> },
     // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
     // That's not the end user experience we should strive for.
     // Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working.
@@ -93,7 +93,11 @@ pub enum ProjectWorkspace {
     // //
     /// Project with a set of disjoint files, not belonging to any particular workspace.
     /// Backed by basic sysroot crates for basic completion and highlighting.
-    DetachedFiles { files: Vec<AbsPathBuf>, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
+    DetachedFiles {
+        files: Vec<AbsPathBuf>,
+        sysroot: Result<Sysroot, Option<String>>,
+        rustc_cfg: Vec<CfgFlag>,
+    },
 }
 
 impl fmt::Debug for ProjectWorkspace {
@@ -113,7 +117,7 @@ impl fmt::Debug for ProjectWorkspace {
                 .debug_struct("Cargo")
                 .field("root", &cargo.workspace_root().file_name())
                 .field("n_packages", &cargo.packages().len())
-                .field("sysroot", &sysroot.is_some())
+                .field("sysroot", &sysroot.is_ok())
                 .field(
                     "n_rustc_compiler_crates",
                     &rustc.as_ref().map_or(0, |(rc, _)| rc.packages().len()),
@@ -126,7 +130,7 @@ impl fmt::Debug for ProjectWorkspace {
             ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
                 let mut debug_struct = f.debug_struct("Json");
                 debug_struct.field("n_crates", &project.n_crates());
-                if let Some(sysroot) = sysroot {
+                if let Ok(sysroot) = sysroot {
                     debug_struct.field("n_sysroot_crates", &sysroot.crates().len());
                 }
                 debug_struct.field("n_rustc_cfg", &rustc_cfg.len());
@@ -135,7 +139,7 @@ impl fmt::Debug for ProjectWorkspace {
             ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f
                 .debug_struct("DetachedFiles")
                 .field("n_files", &files.len())
-                .field("sysroot", &sysroot.is_some())
+                .field("sysroot", &sysroot.is_ok())
                 .field("n_rustc_cfg", &rustc_cfg.len())
                 .finish(),
         }
@@ -191,93 +195,81 @@ impl ProjectWorkspace {
                 let cargo = CargoWorkspace::new(meta);
 
                 let sysroot = match (&config.sysroot, &config.sysroot_src) {
-                    (Some(RustcSource::Path(path)), None) => {
-                        match Sysroot::with_sysroot_dir(path.clone()) {
-                            Ok(it) => Some(it),
-                            Err(e) => {
-                                tracing::error!(%e, "Failed to find sysroot at {}.", path.display());
-                                None
-                            }
-                        }
+                    (Some(RustLibSource::Path(path)), None) => {
+                        Sysroot::with_sysroot_dir(path.clone()).map_err(|e| {
+                          Some(format!("Failed to find sysroot at {}:{e}", path.display()))
+                        })
                     }
-                    (Some(RustcSource::Discover), None) => {
-                        match Sysroot::discover(cargo_toml.parent(), &config.extra_env) {
-                            Ok(it) => Some(it),
-                            Err(e) => {
-                                tracing::error!(
-                                    %e,
-                                    "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
-                                    cargo_toml.display()
-                                );
-                                None
-                            }
-                        }
+                    (Some(RustLibSource::Discover), None) => {
+                        Sysroot::discover(cargo_toml.parent(), &config.extra_env).map_err(|e| {
+                            Some(format!("Failed to find sysroot for Cargo.toml file {}. Is rust-src installed? {e}", cargo_toml.display()))
+                        })
                     }
-                    (Some(RustcSource::Path(sysroot)), Some(sysroot_src)) => {
-                        Some(Sysroot::load(sysroot.clone(), sysroot_src.clone()))
+                    (Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => {
+                        Ok(Sysroot::load(sysroot.clone(), sysroot_src.clone()))
                     }
-                    (Some(RustcSource::Discover), Some(sysroot_src)) => {
-                        match Sysroot::discover_with_src_override(
+                    (Some(RustLibSource::Discover), Some(sysroot_src)) => {
+                        Sysroot::discover_with_src_override(
                             cargo_toml.parent(),
                             &config.extra_env,
                             sysroot_src.clone(),
-                        ) {
-                            Ok(it) => Some(it),
-                            Err(e) => {
-                                tracing::error!(
-                                    %e,
-                                    "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
-                                    cargo_toml.display()
-                                );
-                                None
-                            }
-                        }
+                        ).map_err(|e| {
+                            Some(format!("Failed to find sysroot for Cargo.toml file {}. Is rust-src installed? {e}", cargo_toml.display()))
+                        })
                     }
-                    (None, _) => None,
+                    (None, _) => Err(None),
                 };
 
-                if let Some(sysroot) = &sysroot {
+                if let Ok(sysroot) = &sysroot {
                     tracing::info!(workspace = %cargo_toml.display(), src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot");
                 }
 
                 let rustc_dir = match &config.rustc_source {
-                    Some(RustcSource::Path(path)) => ManifestPath::try_from(path.clone()).ok(),
-                    Some(RustcSource::Discover) => {
-                        sysroot.as_ref().and_then(Sysroot::discover_rustc)
+                    Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone())
+                        .map_err(|p| {
+                            Some(format!("rustc source path is not absolute: {}", p.display()))
+                        }),
+                    Some(RustLibSource::Discover) => {
+                        sysroot.as_ref().ok().and_then(Sysroot::discover_rustc).ok_or_else(|| {
+                            Some(format!("Failed to discover rustc source for sysroot."))
+                        })
                     }
-                    None => None,
+                    None => Err(None),
                 };
 
-                let rustc = match rustc_dir {
-                    Some(rustc_dir) => {
-                        tracing::info!(workspace = %cargo_toml.display(), rustc_dir = %rustc_dir.display(), "Using rustc source");
-                        match CargoWorkspace::fetch_metadata(
-                            &rustc_dir,
-                            cargo_toml.parent(),
-                            config,
-                            progress,
-                        ) {
-                            Ok(meta) => {
-                                let workspace = CargoWorkspace::new(meta);
-                                let buildscripts = WorkspaceBuildScripts::rustc_crates(
-                                    &workspace,
-                                    cargo_toml.parent(),
-                                    &config.extra_env,
-                                );
-                                Some((workspace, buildscripts))
-                            }
-                            Err(e) => {
-                                tracing::error!(
-                                    %e,
-                                    "Failed to read Cargo metadata from rustc source at {}",
-                                    rustc_dir.display()
-                                );
-                                None
-                            }
+                let rustc =  rustc_dir.and_then(|rustc_dir| {
+                    tracing::info!(workspace = %cargo_toml.display(), rustc_dir = %rustc_dir.display(), "Using rustc source");
+                    match CargoWorkspace::fetch_metadata(
+                        &rustc_dir,
+                        cargo_toml.parent(),
+                        &CargoConfig {
+                            features: crate::CargoFeatures::default(),
+                            ..config.clone()
+                        },
+                        progress,
+                    ) {
+                        Ok(meta) => {
+                            let workspace = CargoWorkspace::new(meta);
+                            let buildscripts = WorkspaceBuildScripts::rustc_crates(
+                                &workspace,
+                                cargo_toml.parent(),
+                                &config.extra_env,
+                            );
+                            Ok((workspace, buildscripts))
+                        }
+                        Err(e) => {
+                            tracing::error!(
+                                %e,
+                                "Failed to read Cargo metadata from rustc source at {}",
+                                rustc_dir.display()
+                            );
+                            Err(Some(format!(
+                                "Failed to read Cargo metadata from rustc source at {}: {e}",
+                                rustc_dir.display())
+                            ))
                         }
                     }
-                    None => None,
-                };
+                });
 
                 let rustc_cfg =
                     rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), &config.extra_env);
@@ -313,12 +305,12 @@ impl ProjectWorkspace {
         extra_env: &FxHashMap<String, String>,
     ) -> ProjectWorkspace {
         let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
-            (Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)),
+            (Some(sysroot), Some(sysroot_src)) => Ok(Sysroot::load(sysroot, sysroot_src)),
             (Some(sysroot), None) => {
                 // assume sysroot is structured like rustup's and guess `sysroot_src`
                 let sysroot_src =
                     sysroot.join("lib").join("rustlib").join("src").join("rust").join("library");
-                Some(Sysroot::load(sysroot, sysroot_src))
+                Ok(Sysroot::load(sysroot, sysroot_src))
             }
             (None, Some(sysroot_src)) => {
                 // assume sysroot is structured like rustup's and guess `sysroot`
@@ -326,11 +318,11 @@ impl ProjectWorkspace {
                 for _ in 0..5 {
                     sysroot.pop();
                 }
-                Some(Sysroot::load(sysroot, sysroot_src))
+                Ok(Sysroot::load(sysroot, sysroot_src))
             }
-            (None, None) => None,
+            (None, None) => Err(None),
         };
-        if let Some(sysroot) = &sysroot {
+        if let Ok(sysroot) = &sysroot {
             tracing::info!(src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot");
         }
 
@@ -343,33 +335,23 @@ impl ProjectWorkspace {
         config: &CargoConfig,
     ) -> Result<ProjectWorkspace> {
         let sysroot = match &config.sysroot {
-            Some(RustcSource::Path(path)) => match Sysroot::with_sysroot_dir(path.clone()) {
-                Ok(it) => Some(it),
-                Err(e) => {
-                    tracing::error!(%e, "Failed to find sysroot at {}.", path.display());
-                    None
-                }
-            },
-            Some(RustcSource::Discover) => {
+            Some(RustLibSource::Path(path)) => Sysroot::with_sysroot_dir(path.clone())
+                .map_err(|e| Some(format!("Failed to find sysroot at {}:{e}", path.display()))),
+            Some(RustLibSource::Discover) => {
                 let dir = &detached_files
                     .first()
                     .and_then(|it| it.parent())
                     .ok_or_else(|| format_err!("No detached files to load"))?;
-                match Sysroot::discover(dir, &config.extra_env) {
-                    Ok(it) => Some(it),
-                    Err(e) => {
-                        tracing::error!(
-                            %e,
-                            "Failed to find sysroot for {}. Is rust-src installed?",
-                            dir.display()
-                        );
-                        None
-                    }
-                }
+                Sysroot::discover(dir, &config.extra_env).map_err(|e| {
+                    Some(format!(
+                        "Failed to find sysroot for {}. Is rust-src installed? {e}",
+                        dir.display()
+                    ))
+                })
             }
-            None => None,
+            None => Err(None),
         };
-        if let Some(sysroot) = &sysroot {
+        if let Ok(sysroot) = &sysroot {
             tracing::info!(src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot");
         }
         let rustc_cfg = rustc_cfg::get(None, None, &Default::default());
@@ -450,10 +432,18 @@ impl ProjectWorkspace {
         }
     }
 
+    pub fn workspace_definition_path(&self) -> Option<&AbsPath> {
+        match self {
+            ProjectWorkspace::Cargo { cargo, .. } => Some(cargo.workspace_root()),
+            ProjectWorkspace::Json { project, .. } => Some(project.path()),
+            ProjectWorkspace::DetachedFiles { .. } => None,
+        }
+    }
+
     pub fn find_sysroot_proc_macro_srv(&self) -> Option<AbsPathBuf> {
         match self {
-            ProjectWorkspace::Cargo { sysroot: Some(sysroot), .. }
-            | ProjectWorkspace::Json { sysroot: Some(sysroot), .. } => {
+            ProjectWorkspace::Cargo { sysroot: Ok(sysroot), .. }
+            | ProjectWorkspace::Json { sysroot: Ok(sysroot), .. } => {
                 let standalone_server_name =
                     format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
                 ["libexec", "lib"]
@@ -469,7 +459,7 @@ impl ProjectWorkspace {
     /// The return type contains the path and whether or not
     /// the root is a member of the current workspace
     pub fn to_roots(&self) -> Vec<PackageRoot> {
-        let mk_sysroot = |sysroot: Option<&Sysroot>, project_root: Option<&AbsPath>| {
+        let mk_sysroot = |sysroot: Result<&Sysroot, _>, project_root: Option<&AbsPath>| {
             sysroot.map(|sysroot| PackageRoot {
                 // mark the sysroot as mutable if it is located inside of the project
                 is_local: project_root
@@ -592,7 +582,7 @@ impl ProjectWorkspace {
                 load_proc_macro,
                 load,
                 project,
-                sysroot.as_ref(),
+                sysroot.as_ref().ok(),
                 extra_env,
                 Err("rust-project.json projects have no target layout set".into()),
             ),
@@ -608,9 +598,9 @@ impl ProjectWorkspace {
             } => cargo_to_crate_graph(
                 load_proc_macro,
                 load,
-                rustc,
+                rustc.as_ref().ok(),
                 cargo,
-                sysroot.as_ref(),
+                sysroot.as_ref().ok(),
                 rustc_cfg.clone(),
                 cfg_overrides,
                 build_scripts,
@@ -624,7 +614,7 @@ impl ProjectWorkspace {
                     rustc_cfg.clone(),
                     load,
                     files,
-                    sysroot,
+                    sysroot.as_ref().ok(),
                     Err("detached file projects have no target layout set".into()),
                 )
             }
@@ -786,7 +776,7 @@ fn project_json_to_crate_graph(
 fn cargo_to_crate_graph(
     load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
-    rustc: &Option<(CargoWorkspace, WorkspaceBuildScripts)>,
+    rustc: Option<&(CargoWorkspace, WorkspaceBuildScripts)>,
     cargo: &CargoWorkspace,
     sysroot: Option<&Sysroot>,
     rustc_cfg: Vec<CfgFlag>,
@@ -932,7 +922,7 @@ fn cargo_to_crate_graph(
     if has_private {
         // If the user provided a path to rustc sources, we add all the rustc_private crates
         // and create dependencies on them for the crates which opt-in to that
-        if let Some((rustc_workspace, build_scripts)) = rustc {
+        if let Some((rustc_workspace, rustc_build_scripts)) = rustc {
             handle_rustc_crates(
                 &mut crate_graph,
                 &mut pkg_to_lib_crate,
@@ -945,7 +935,13 @@ fn cargo_to_crate_graph(
                 &pkg_crates,
                 &cfg_options,
                 override_cfg,
-                build_scripts,
+                if rustc_workspace.workspace_root() == cargo.workspace_root() {
+                    // the rustc workspace does not use the installed toolchain's proc-macro server
+                    // so we need to make sure we don't use the pre compiled proc-macros there either
+                    build_scripts
+                } else {
+                    rustc_build_scripts
+                },
                 target_layout,
             );
         }
@@ -957,7 +953,7 @@ fn detached_files_to_crate_graph(
     rustc_cfg: Vec<CfgFlag>,
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     detached_files: &[AbsPathBuf],
-    sysroot: &Option<Sysroot>,
+    sysroot: Option<&Sysroot>,
     target_layout: TargetLayoutLoadResult,
 ) -> CrateGraph {
     let _p = profile::span("detached_files_to_crate_graph");
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index e8c10927d62..6ce1de5d32b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -7,7 +7,7 @@ use std::{
 };
 
 use hir::{
-    db::{AstDatabase, DefDatabase, HirDatabase},
+    db::{DefDatabase, ExpandDatabase, HirDatabase},
     AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef,
 };
 use hir_def::{
@@ -24,7 +24,7 @@ use ide_db::base_db::{
 use itertools::Itertools;
 use oorandom::Rand32;
 use profile::{Bytes, StopWatch};
-use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustcSource};
+use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource};
 use rayon::prelude::*;
 use rustc_hash::FxHashSet;
 use stdx::format_to;
@@ -57,7 +57,7 @@ impl flags::AnalysisStats {
         let mut cargo_config = CargoConfig::default();
         cargo_config.sysroot = match self.no_sysroot {
             true => None,
-            false => Some(RustcSource::Discover),
+            false => Some(RustLibSource::Discover),
         };
         let no_progress = &|_| ();
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
index 0721d486ef1..4006d023def 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -1,7 +1,7 @@
 //! Analyze all modules in a project for diagnostics. Exits with a non-zero
 //! status code if any errors are found.
 
-use project_model::{CargoConfig, RustcSource};
+use project_model::{CargoConfig, RustLibSource};
 use rustc_hash::FxHashSet;
 
 use hir::{db::HirDatabase, Crate, Module};
@@ -16,7 +16,7 @@ use crate::cli::{
 impl flags::Diagnostics {
     pub fn run(self) -> anyhow::Result<()> {
         let mut cargo_config = CargoConfig::default();
-        cargo_config.sysroot = Some(RustcSource::Discover);
+        cargo_config.sysroot = Some(RustLibSource::Discover);
         let load_cargo_config = LoadCargoConfig {
             load_out_dirs_from_check: !self.disable_build_scripts,
             with_proc_macro_server: ProcMacroServerChoice::Sysroot,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
index 9b5451496c6..7f5d0844967 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
@@ -13,7 +13,7 @@ use ide_db::LineIndexDatabase;
 use ide_db::base_db::salsa::{self, ParallelDatabase};
 use ide_db::line_index::WideEncoding;
 use lsp_types::{self, lsif};
-use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustcSource};
+use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource};
 use vfs::{AbsPathBuf, Vfs};
 
 use crate::cli::load_cargo::ProcMacroServerChoice;
@@ -290,7 +290,7 @@ impl flags::Lsif {
         eprintln!("Generating LSIF started...");
         let now = Instant::now();
         let mut cargo_config = CargoConfig::default();
-        cargo_config.sysroot = Some(RustcSource::Discover);
+        cargo_config.sysroot = Some(RustLibSource::Discover);
         let no_progress = &|_| ();
         let load_cargo_config = LoadCargoConfig {
             load_out_dirs_from_check: true,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index df5c26cf77a..3e5e40750e9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -15,7 +15,7 @@ use ide::{
     TokenStaticData,
 };
 use ide_db::LineIndexDatabase;
-use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustcSource};
+use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource};
 use scip::types as scip_types;
 use std::env;
 
@@ -30,7 +30,7 @@ impl flags::Scip {
         eprintln!("Generating SCIP start...");
         let now = Instant::now();
         let mut cargo_config = CargoConfig::default();
-        cargo_config.sysroot = Some(RustcSource::Discover);
+        cargo_config.sysroot = Some(RustLibSource::Discover);
 
         let no_progress = &|s| (eprintln!("rust-analyzer: Loading {s}"));
         let load_cargo_config = LoadCargoConfig {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs
index 35a874f8920..82a769347df 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs
@@ -1,7 +1,7 @@
 //! Applies structured search replace rules from the command line.
 
 use ide_ssr::MatchFinder;
-use project_model::{CargoConfig, RustcSource};
+use project_model::{CargoConfig, RustLibSource};
 
 use crate::cli::{
     flags,
@@ -13,7 +13,7 @@ impl flags::Ssr {
     pub fn run(self) -> Result<()> {
         use ide_db::base_db::SourceDatabaseExt;
         let mut cargo_config = CargoConfig::default();
-        cargo_config.sysroot = Some(RustcSource::Discover);
+        cargo_config.sysroot = Some(RustLibSource::Discover);
         let load_cargo_config = LoadCargoConfig {
             load_out_dirs_from_check: true,
             with_proc_macro_server: ProcMacroServerChoice::Sysroot,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 75233dbb2ab..c35cce103fa 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -22,7 +22,7 @@ use ide_db::{
 use itertools::Itertools;
 use lsp_types::{ClientCapabilities, MarkupKind};
 use project_model::{
-    CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource,
+    CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustLibSource,
     UnsetTestCrates,
 };
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -272,7 +272,6 @@ config_data! {
         /// The warnings will be indicated by a blue squiggly underline in code
         /// and a blue icon in the `Problems Panel`.
         diagnostics_warningsAsInfo: Vec<String> = "[]",
-
         /// These directories will be ignored by rust-analyzer. They are
         /// relative to the workspace root, and globs are not supported. You may
         /// also need to add the folders to Code's `files.watcherExclude`.
@@ -895,6 +894,15 @@ impl Config {
         }
     }
 
+    pub fn add_linked_projects(&mut self, linked_projects: Vec<ProjectJsonData>) {
+        let mut linked_projects = linked_projects
+            .into_iter()
+            .map(ManifestOrProjectJson::ProjectJson)
+            .collect::<Vec<ManifestOrProjectJson>>();
+
+        self.data.linkedProjects.append(&mut linked_projects);
+    }
+
     pub fn did_save_text_document_dynamic_registration(&self) -> bool {
         let caps = try_or_def!(self.caps.text_document.as_ref()?.synchronization.clone()?);
         caps.did_save == Some(true) && caps.dynamic_registration == Some(true)
@@ -1129,16 +1137,16 @@ impl Config {
     pub fn cargo(&self) -> CargoConfig {
         let rustc_source = self.data.rustc_source.as_ref().map(|rustc_src| {
             if rustc_src == "discover" {
-                RustcSource::Discover
+                RustLibSource::Discover
             } else {
-                RustcSource::Path(self.root_path.join(rustc_src))
+                RustLibSource::Path(self.root_path.join(rustc_src))
             }
         });
         let sysroot = self.data.cargo_sysroot.as_ref().map(|sysroot| {
             if sysroot == "discover" {
-                RustcSource::Discover
+                RustLibSource::Discover
             } else {
-                RustcSource::Path(self.root_path.join(sysroot))
+                RustLibSource::Path(self.root_path.join(sysroot))
             }
         });
         let sysroot_src =
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
index 715804449a0..313bb2ec8df 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
@@ -88,6 +88,42 @@ impl<'a> RequestDispatcher<'a> {
     }
 
     /// Dispatches the request onto thread pool
+    pub(crate) fn on_no_retry<R>(
+        &mut self,
+        f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
+    ) -> &mut Self
+    where
+        R: lsp_types::request::Request + 'static,
+        R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
+        R::Result: Serialize,
+    {
+        let (req, params, panic_context) = match self.parse::<R>() {
+            Some(it) => it,
+            None => return self,
+        };
+
+        self.global_state.task_pool.handle.spawn({
+            let world = self.global_state.snapshot();
+            move || {
+                let result = panic::catch_unwind(move || {
+                    let _pctx = stdx::panic_context::enter(panic_context);
+                    f(world, params)
+                });
+                match thread_result_to_response::<R>(req.id.clone(), result) {
+                    Ok(response) => Task::Response(response),
+                    Err(_) => Task::Response(lsp_server::Response::new_err(
+                        req.id,
+                        lsp_server::ErrorCode::ContentModified as i32,
+                        "content modified".to_string(),
+                    )),
+                }
+            }
+        });
+
+        self
+    }
+
+    /// Dispatches the request onto thread pool
     pub(crate) fn on<R>(
         &mut self,
         f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
index 32ac9a42dec..2fca2ab851d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
@@ -29,7 +29,7 @@ use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
 use serde_json::json;
 use stdx::{format_to, never};
 use syntax::{algo, ast, AstNode, TextRange, TextSize};
-use vfs::AbsPathBuf;
+use vfs::{AbsPath, AbsPathBuf};
 
 use crate::{
     cargo_target_spec::CargoTargetSpec,
@@ -46,6 +46,7 @@ use crate::{
 pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<()> {
     state.proc_macro_clients.clear();
     state.proc_macro_changed = false;
+
     state.fetch_workspaces_queue.request_op("reload workspace request".to_string());
     state.fetch_build_data_queue.request_op("reload workspace request".to_string());
     Ok(())
@@ -84,6 +85,15 @@ pub(crate) fn handle_analyzer_status(
             snap.workspaces.len(),
             if snap.workspaces.len() == 1 { "" } else { "s" }
         );
+
+        format_to!(
+            buf,
+            "Workspace root folders: {:?}",
+            snap.workspaces
+                .iter()
+                .flat_map(|ws| ws.workspace_definition_path())
+                .collect::<Vec<&AbsPath>>()
+        );
     }
     buf.push_str("\nAnalysis:\n");
     buf.push_str(
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs
index 30f1c53c198..12e5caf2cc9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs
@@ -36,11 +36,41 @@ impl Progress {
 }
 
 impl GlobalState {
-    pub(crate) fn show_message(&mut self, typ: lsp_types::MessageType, message: String) {
-        let message = message;
-        self.send_notification::<lsp_types::notification::ShowMessage>(
-            lsp_types::ShowMessageParams { typ, message },
-        )
+    pub(crate) fn show_message(
+        &mut self,
+        typ: lsp_types::MessageType,
+        message: String,
+        show_open_log_button: bool,
+    ) {
+        match self.config.open_server_logs() && show_open_log_button  {
+            true => self.send_request::<lsp_types::request::ShowMessageRequest>(
+                lsp_types::ShowMessageRequestParams {
+                    typ,
+                    message,
+                    actions: Some(vec![lsp_types::MessageActionItem {
+                        title: "Open server logs".to_owned(),
+                        properties: Default::default(),
+                    }]),
+                },
+                |this, resp| {
+                    let lsp_server::Response { error: None, result: Some(result), .. } = resp
+                    else { return };
+                    if let Ok(Some(_item)) = crate::from_json::<
+                        <lsp_types::request::ShowMessageRequest as lsp_types::request::Request>::Result,
+                    >(
+                        lsp_types::request::ShowMessageRequest::METHOD, &result
+                    ) {
+                        this.send_notification::<lsp_ext::OpenServerLogs>(());
+                    }
+                },
+            ),
+            false => self.send_notification::<lsp_types::notification::ShowMessage>(
+                lsp_types::ShowMessageParams {
+                    typ,
+                    message,
+                },
+            ),
+        }
     }
 
     /// Sends a notification to the client containing the error `message`.
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index dd0804b4398..67a54cde68c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -406,9 +406,19 @@ impl GlobalState {
 
             if self.config.server_status_notification() {
                 self.send_notification::<lsp_ext::ServerStatusNotification>(status);
-            } else if let (lsp_ext::Health::Error, Some(message)) = (status.health, &status.message)
-            {
-                self.show_and_log_error(message.clone(), None);
+            } else if let (health, Some(message)) = (status.health, &status.message) {
+                let open_log_button = tracing::enabled!(tracing::Level::ERROR)
+                    && (self.fetch_build_data_error().is_err()
+                        || self.fetch_workspace_error().is_err());
+                self.show_message(
+                    match health {
+                        lsp_ext::Health::Ok => lsp_types::MessageType::INFO,
+                        lsp_ext::Health::Warning => lsp_types::MessageType::WARNING,
+                        lsp_ext::Health::Error => lsp_types::MessageType::ERROR,
+                    },
+                    message.clone(),
+                    open_log_button,
+                );
             }
         }
     }
@@ -653,7 +663,7 @@ impl GlobalState {
             .on::<lsp_types::request::GotoDeclaration>(handlers::handle_goto_declaration)
             .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)
             .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
-            .on::<lsp_types::request::InlayHintRequest>(handlers::handle_inlay_hints)
+            .on_no_retry::<lsp_types::request::InlayHintRequest>(handlers::handle_inlay_hints)
             .on::<lsp_types::request::InlayHintResolveRequest>(handlers::handle_inlay_hints_resolve)
             .on::<lsp_types::request::Completion>(handlers::handle_completion)
             .on::<lsp_types::request::ResolveCompletionItem>(handlers::handle_completion_resolve)
@@ -919,6 +929,7 @@ impl GlobalState {
                                         this.show_message(
                                             lsp_types::MessageType::WARNING,
                                             error.to_string(),
+                                            false,
                                         );
                                     }
                                     this.update_configuration(config);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 28d37f5685a..1a6e1af2eb7 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -90,38 +90,55 @@ impl GlobalState {
             quiescent: self.is_quiescent(),
             message: None,
         };
+        let mut message = String::new();
 
         if self.proc_macro_changed {
             status.health = lsp_ext::Health::Warning;
-            status.message =
-                Some("Reload required due to source changes of a procedural macro.".into())
+            message.push_str("Reload required due to source changes of a procedural macro.\n\n");
         }
         if let Err(_) = self.fetch_build_data_error() {
             status.health = lsp_ext::Health::Warning;
-            status.message =
-                Some("Failed to run build scripts of some packages, check the logs.".to_string());
+            message.push_str("Failed to run build scripts of some packages.\n\n");
         }
         if !self.config.cargo_autoreload()
             && self.is_quiescent()
             && self.fetch_workspaces_queue.op_requested()
         {
             status.health = lsp_ext::Health::Warning;
-            status.message = Some("Workspace reload required".to_string())
+            message.push_str("Auto-reloading is disabled and the workspace has changed, a manual workspace reload is required.\n\n");
         }
-
-        if let Err(_) = self.fetch_workspace_error() {
-            status.health = lsp_ext::Health::Error;
-            status.message = Some("Failed to load workspaces".to_string())
-        }
-
         if self.config.linked_projects().is_empty()
             && self.config.detached_files().is_empty()
             && self.config.notifications().cargo_toml_not_found
         {
             status.health = lsp_ext::Health::Warning;
-            status.message = Some("Failed to discover workspace".to_string())
+            message.push_str("Failed to discover workspace.\n\n");
+        }
+
+        for ws in self.workspaces.iter() {
+            let (ProjectWorkspace::Cargo { sysroot, .. }
+            | ProjectWorkspace::Json { sysroot, .. }
+            | ProjectWorkspace::DetachedFiles { sysroot, .. }) = ws;
+            if let Err(Some(e)) = sysroot {
+                status.health = lsp_ext::Health::Warning;
+                message.push_str(e);
+                message.push_str("\n\n");
+            }
+            if let ProjectWorkspace::Cargo { rustc: Err(Some(e)), .. } = ws {
+                status.health = lsp_ext::Health::Warning;
+                message.push_str(e);
+                message.push_str("\n\n");
+            }
         }
 
+        if let Err(_) = self.fetch_workspace_error() {
+            status.health = lsp_ext::Health::Error;
+            message.push_str("Failed to load workspaces.\n\n");
+        }
+
+        if !message.is_empty() {
+            status.message = Some(message.trim_end().to_owned());
+        }
         status
     }
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
index db66d08a73b..c43d0830b9e 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
@@ -48,23 +48,30 @@ impl From<ast::IfExpr> for ElseBranch {
 }
 
 impl ast::IfExpr {
-    pub fn then_branch(&self) -> Option<ast::BlockExpr> {
-        self.children_after_condition().next()
+    pub fn condition(&self) -> Option<ast::Expr> {
+        // If the condition is a BlockExpr, check if the then body is missing.
+        // If it is assume the condition is the expression that is missing instead.
+        let mut exprs = support::children(self.syntax());
+        let first = exprs.next();
+        match first {
+            Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
+            first => first,
+        }
     }
 
-    pub fn else_branch(&self) -> Option<ElseBranch> {
-        let res = match self.children_after_condition().nth(1) {
-            Some(block) => ElseBranch::Block(block),
-            None => {
-                let elif = self.children_after_condition().next()?;
-                ElseBranch::IfExpr(elif)
-            }
-        };
-        Some(res)
+    pub fn then_branch(&self) -> Option<ast::BlockExpr> {
+        match support::children(self.syntax()).nth(1)? {
+            ast::Expr::BlockExpr(block) => Some(block),
+            _ => None,
+        }
     }
 
-    fn children_after_condition<N: AstNode>(&self) -> impl Iterator<Item = N> {
-        self.syntax().children().skip(1).filter_map(N::cast)
+    pub fn else_branch(&self) -> Option<ElseBranch> {
+        match support::children(self.syntax()).nth(2)? {
+            ast::Expr::BlockExpr(block) => Some(ElseBranch::Block(block)),
+            ast::Expr::IfExpr(elif) => Some(ElseBranch::IfExpr(elif)),
+            _ => None,
+        }
     }
 }
 
@@ -356,7 +363,15 @@ impl ast::BlockExpr {
             Some(it) => it,
             None => return true,
         };
-        !matches!(parent.kind(), FN | IF_EXPR | WHILE_EXPR | LOOP_EXPR)
+        match parent.kind() {
+            FOR_EXPR | IF_EXPR => parent
+                .children()
+                .filter(|it| ast::Expr::can_cast(it.kind()))
+                .next()
+                .map_or(true, |it| it == *self.syntax()),
+            LET_ELSE | FN | WHILE_EXPR | LOOP_EXPR | CONST_BLOCK_PAT => false,
+            _ => true,
+        }
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
index 15bd5ab3c72..3308077da5b 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
@@ -937,12 +937,6 @@ impl From<ast::Adt> for ast::Item {
     }
 }
 
-impl ast::IfExpr {
-    pub fn condition(&self) -> Option<ast::Expr> {
-        support::child(&self.syntax)
-    }
-}
-
 impl ast::MatchGuard {
     pub fn condition(&self) -> Option<ast::Expr> {
         support::child(&self.syntax)
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index 93ff76a040c..ca6de4061a4 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -44,6 +44,8 @@
 //!     try: infallible
 //!     unsize: sized
 
+#![rustc_coherence_is_core]
+
 pub mod marker {
     // region:sized
     #[lang = "sized"]
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index a3b1a3107d0..c5eb08748bf 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -200,6 +200,11 @@
                 "category": "rust-analyzer"
             },
             {
+                "command": "rust-analyzer.addProject",
+                "title": "Add current file's crate to workspace",
+                "category": "rust-analyzer"
+            },
+            {
                 "command": "rust-analyzer.reload",
                 "title": "Restart server",
                 "category": "rust-analyzer"
@@ -428,6 +433,17 @@
                     "default": false,
                     "type": "boolean"
                 },
+                "rust-analyzer.discoverProjectCommand": {
+                    "markdownDescription": "Sets the command that rust-analyzer uses to generate `rust-project.json` files. This command should only be used\n if a build system like Buck or Bazel is also in use. The command must accept files as arguments and return \n a rust-project.json over stdout.",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "array"
+                    ],
+                    "items": {
+                        "type": "string"
+                    }
+                },
                 "$generated-start": {},
                 "rust-analyzer.assist.emitMustUse": {
                     "markdownDescription": "Whether to insert #[must_use] when generating `as_` methods\nfor enum variants.",
diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts
index 62980ca0464..565cb9c6432 100644
--- a/src/tools/rust-analyzer/editors/code/src/client.ts
+++ b/src/tools/rust-analyzer/editors/code/src/client.ts
@@ -6,7 +6,7 @@ import * as Is from "vscode-languageclient/lib/common/utils/is";
 import { assert } from "./util";
 import * as diagnostics from "./diagnostics";
 import { WorkspaceEdit } from "vscode";
-import { Config, substituteVSCodeVariables } from "./config";
+import { Config, prepareVSCodeConfig } from "./config";
 import { randomUUID } from "crypto";
 
 export interface Env {
@@ -95,7 +95,16 @@ export async function createClient(
                     const resp = await next(params, token);
                     if (resp && Array.isArray(resp)) {
                         return resp.map((val) => {
-                            return substituteVSCodeVariables(val);
+                            return prepareVSCodeConfig(val, (key, cfg) => {
+                                // we only want to set discovered workspaces on the right key
+                                // and if a workspace has been discovered.
+                                if (
+                                    key === "linkedProjects" &&
+                                    config.discoveredWorkspaces.length > 0
+                                ) {
+                                    cfg[key] = config.discoveredWorkspaces;
+                                }
+                            });
                         });
                     } else {
                         return resp;
diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts
index f4a4579a92c..8a953577e99 100644
--- a/src/tools/rust-analyzer/editors/code/src/commands.ts
+++ b/src/tools/rust-analyzer/editors/code/src/commands.ts
@@ -3,7 +3,7 @@ import * as lc from "vscode-languageclient";
 import * as ra from "./lsp_ext";
 import * as path from "path";
 
-import { Ctx, Cmd, CtxInit } from "./ctx";
+import { Ctx, Cmd, CtxInit, discoverWorkspace } from "./ctx";
 import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets";
 import { spawnSync } from "child_process";
 import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
@@ -749,6 +749,33 @@ export function reloadWorkspace(ctx: CtxInit): Cmd {
     return async () => ctx.client.sendRequest(ra.reloadWorkspace);
 }
 
+export function addProject(ctx: CtxInit): Cmd {
+    return async () => {
+        const discoverProjectCommand = ctx.config.discoverProjectCommand;
+        if (!discoverProjectCommand) {
+            return;
+        }
+
+        const workspaces: JsonProject[] = await Promise.all(
+            vscode.workspace.workspaceFolders!.map(async (folder): Promise<JsonProject> => {
+                const rustDocuments = vscode.workspace.textDocuments.filter(isRustDocument);
+                return discoverWorkspace(rustDocuments, discoverProjectCommand, {
+                    cwd: folder.uri.fsPath,
+                });
+            })
+        );
+
+        ctx.addToDiscoveredWorkspaces(workspaces);
+
+        // this is a workaround to avoid needing writing the `rust-project.json` into
+        // a workspace-level VS Code-specific settings folder. We'd like to keep the
+        // `rust-project.json` entirely in-memory.
+        await ctx.client?.sendNotification(lc.DidChangeConfigurationNotification.type, {
+            settings: "",
+        });
+    };
+}
+
 async function showReferencesImpl(
     client: LanguageClient | undefined,
     uri: string,
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index 1faa0ad9106..da7c74c28ba 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -34,6 +34,7 @@ export class Config {
 
     constructor(ctx: vscode.ExtensionContext) {
         this.globalStorageUri = ctx.globalStorageUri;
+        this.discoveredWorkspaces = [];
         vscode.workspace.onDidChangeConfiguration(
             this.onDidChangeConfiguration,
             this,
@@ -55,6 +56,8 @@ export class Config {
         log.info("Using configuration", Object.fromEntries(cfg));
     }
 
+    public discoveredWorkspaces: JsonProject[];
+
     private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) {
         this.refreshLogging();
 
@@ -191,7 +194,7 @@ export class Config {
      * So this getter handles this quirk by not requiring the caller to use postfix `!`
      */
     private get<T>(path: string): T | undefined {
-        return substituteVSCodeVariables(this.cfg.get<T>(path));
+        return prepareVSCodeConfig(this.cfg.get<T>(path));
     }
 
     get serverPath() {
@@ -214,6 +217,10 @@ export class Config {
         return this.get<boolean>("trace.extension");
     }
 
+    get discoverProjectCommand() {
+        return this.get<string[] | undefined>("discoverProjectCommand");
+    }
+
     get cargoRunner() {
         return this.get<string | undefined>("cargoRunner");
     }
@@ -280,18 +287,32 @@ export class Config {
     }
 }
 
-export function substituteVSCodeVariables<T>(resp: T): T {
+// the optional `cb?` parameter is meant to be used to add additional
+// key/value pairs to the VS Code configuration. This needed for, e.g.,
+// including a `rust-project.json` into the `linkedProjects` key as part
+// of the configuration/InitializationParams _without_ causing VS Code
+// configuration to be written out to workspace-level settings. This is
+// undesirable behavior because rust-project.json files can be tens of
+// thousands of lines of JSON, most of which is not meant for humans
+// to interact with.
+export function prepareVSCodeConfig<T>(
+    resp: T,
+    cb?: (key: Extract<keyof T, string>, res: { [key: string]: any }) => void
+): T {
     if (Is.string(resp)) {
         return substituteVSCodeVariableInString(resp) as T;
     } else if (resp && Is.array<any>(resp)) {
         return resp.map((val) => {
-            return substituteVSCodeVariables(val);
+            return prepareVSCodeConfig(val);
         }) as T;
     } else if (resp && typeof resp === "object") {
         const res: { [key: string]: any } = {};
         for (const key in resp) {
             const val = resp[key];
-            res[key] = substituteVSCodeVariables(val);
+            res[key] = prepareVSCodeConfig(val);
+            if (cb) {
+                cb(key, res);
+            }
         }
         return res as T;
     }
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index 1708d47cee7..c2dca733df8 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -2,12 +2,20 @@ import * as vscode from "vscode";
 import * as lc from "vscode-languageclient/node";
 import * as ra from "./lsp_ext";
 
-import { Config, substituteVSCodeVariables } from "./config";
+import { Config, prepareVSCodeConfig } from "./config";
 import { createClient } from "./client";
-import { isRustDocument, isRustEditor, LazyOutputChannel, log, RustEditor } from "./util";
+import {
+    executeDiscoverProject,
+    isRustDocument,
+    isRustEditor,
+    LazyOutputChannel,
+    log,
+    RustEditor,
+} from "./util";
 import { ServerStatusParams } from "./lsp_ext";
 import { PersistentState } from "./persistent_state";
 import { bootstrap } from "./bootstrap";
+import { ExecOptions } from "child_process";
 
 // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
 // only those are in use. We use "Empty" to represent these scenarios
@@ -41,6 +49,17 @@ export function fetchWorkspace(): Workspace {
         : { kind: "Workspace Folder" };
 }
 
+export async function discoverWorkspace(
+    files: readonly vscode.TextDocument[],
+    command: string[],
+    options: ExecOptions
+): Promise<JsonProject> {
+    const paths = files.map((f) => `"${f.uri.fsPath}"`).join(" ");
+    const joinedCommand = command.join(" ");
+    const data = await executeDiscoverProject(`${joinedCommand} ${paths}`, options);
+    return JSON.parse(data) as JsonProject;
+}
+
 export type CommandFactory = {
     enabled: (ctx: CtxInit) => Cmd;
     disabled?: (ctx: Ctx) => Cmd;
@@ -52,7 +71,7 @@ export type CtxInit = Ctx & {
 
 export class Ctx {
     readonly statusBar: vscode.StatusBarItem;
-    readonly config: Config;
+    config: Config;
     readonly workspace: Workspace;
 
     private _client: lc.LanguageClient | undefined;
@@ -169,7 +188,30 @@ export class Ctx {
                 };
             }
 
-            const initializationOptions = substituteVSCodeVariables(rawInitializationOptions);
+            const discoverProjectCommand = this.config.discoverProjectCommand;
+            if (discoverProjectCommand) {
+                const workspaces: JsonProject[] = await Promise.all(
+                    vscode.workspace.workspaceFolders!.map(async (folder): Promise<JsonProject> => {
+                        const rustDocuments = vscode.workspace.textDocuments.filter(isRustDocument);
+                        return discoverWorkspace(rustDocuments, discoverProjectCommand, {
+                            cwd: folder.uri.fsPath,
+                        });
+                    })
+                );
+
+                this.addToDiscoveredWorkspaces(workspaces);
+            }
+
+            const initializationOptions = prepareVSCodeConfig(
+                rawInitializationOptions,
+                (key, obj) => {
+                    // we only want to set discovered workspaces on the right key
+                    // and if a workspace has been discovered.
+                    if (key === "linkedProjects" && this.config.discoveredWorkspaces.length > 0) {
+                        obj["linkedProjects"] = this.config.discoveredWorkspaces;
+                    }
+                }
+            );
 
             this._client = await createClient(
                 this.traceOutputChannel,
@@ -251,6 +293,17 @@ export class Ctx {
         return this._serverPath;
     }
 
+    addToDiscoveredWorkspaces(workspaces: JsonProject[]) {
+        for (const workspace of workspaces) {
+            const index = this.config.discoveredWorkspaces.indexOf(workspace);
+            if (~index) {
+                this.config.discoveredWorkspaces[index] = workspace;
+            } else {
+                this.config.discoveredWorkspaces.push(workspace);
+            }
+        }
+    }
+
     private updateCommands(forceDisable?: "disable") {
         this.commandDisposables.forEach((disposable) => disposable.dispose());
         this.commandDisposables = [];
@@ -289,6 +342,7 @@ export class Ctx {
                 statusBar.tooltip.appendText(status.message ?? "Ready");
                 statusBar.color = undefined;
                 statusBar.backgroundColor = undefined;
+                statusBar.command = "rust-analyzer.stopServer";
                 break;
             case "warning":
                 if (status.message) {
@@ -298,6 +352,7 @@ export class Ctx {
                 statusBar.backgroundColor = new vscode.ThemeColor(
                     "statusBarItem.warningBackground"
                 );
+                statusBar.command = "rust-analyzer.openLogs";
                 icon = "$(warning) ";
                 break;
             case "error":
@@ -306,6 +361,7 @@ export class Ctx {
                 }
                 statusBar.color = new vscode.ThemeColor("statusBarItem.errorForeground");
                 statusBar.backgroundColor = new vscode.ThemeColor("statusBarItem.errorBackground");
+                statusBar.command = "rust-analyzer.openLogs";
                 icon = "$(error) ";
                 break;
             case "stopped":
@@ -315,18 +371,19 @@ export class Ctx {
                 );
                 statusBar.color = undefined;
                 statusBar.backgroundColor = undefined;
+                statusBar.command = "rust-analyzer.startServer";
                 statusBar.text = `$(stop-circle) rust-analyzer`;
                 return;
         }
         if (statusBar.tooltip.value) {
             statusBar.tooltip.appendText("\n\n");
         }
-        statusBar.tooltip.appendMarkdown("[Stop server](command:rust-analyzer.stopServer)");
         statusBar.tooltip.appendMarkdown(
             "\n\n[Reload Workspace](command:rust-analyzer.reloadWorkspace)"
         );
-        statusBar.tooltip.appendMarkdown("\n\n[Restart server](command:rust-analyzer.startServer)");
         statusBar.tooltip.appendMarkdown("\n\n[Open logs](command:rust-analyzer.openLogs)");
+        statusBar.tooltip.appendMarkdown("\n\n[Restart server](command:rust-analyzer.startServer)");
+        statusBar.tooltip.appendMarkdown("[Stop server](command:rust-analyzer.stopServer)");
         if (!status.quiescent) icon = "$(sync~spin) ";
         statusBar.text = `${icon}rust-analyzer`;
     }
diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
index 400cd207d41..872d7199b83 100644
--- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
+++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
@@ -43,6 +43,7 @@ export const relatedTests = new lc.RequestType<lc.TextDocumentPositionParams, Te
     "rust-analyzer/relatedTests"
 );
 export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace");
+
 export const runFlycheck = new lc.NotificationType<{
     textDocument: lc.TextDocumentIdentifier | null;
 }>("rust-analyzer/runFlycheck");
diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts
index 8a2412af849..d5de00561b1 100644
--- a/src/tools/rust-analyzer/editors/code/src/main.ts
+++ b/src/tools/rust-analyzer/editors/code/src/main.ts
@@ -153,6 +153,7 @@ function createCommands(): Record<string, CommandFactory> {
         memoryUsage: { enabled: commands.memoryUsage },
         shuffleCrateGraph: { enabled: commands.shuffleCrateGraph },
         reloadWorkspace: { enabled: commands.reloadWorkspace },
+        addProject: { enabled: commands.addProject },
         matchingBrace: { enabled: commands.matchingBrace },
         joinLines: { enabled: commands.joinLines },
         parentModule: { enabled: commands.parentModule },
diff --git a/src/tools/rust-analyzer/editors/code/src/rust_project.ts b/src/tools/rust-analyzer/editors/code/src/rust_project.ts
new file mode 100644
index 00000000000..187a1a96c10
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/rust_project.ts
@@ -0,0 +1,91 @@
+interface JsonProject {
+    /// Path to the directory with *source code* of
+    /// sysroot crates.
+    ///
+    /// It should point to the directory where std,
+    /// core, and friends can be found:
+    ///
+    /// https://github.com/rust-lang/rust/tree/master/library.
+    ///
+    /// If provided, rust-analyzer automatically adds
+    /// dependencies on sysroot crates. Conversely,
+    /// if you omit this path, you can specify sysroot
+    /// dependencies yourself and, for example, have
+    /// several different "sysroots" in one graph of
+    /// crates.
+    sysroot_src?: string;
+    /// The set of crates comprising the current
+    /// project. Must include all transitive
+    /// dependencies as well as sysroot crate (libstd,
+    /// libcore and such).
+    crates: Crate[];
+}
+
+interface Crate {
+    /// Optional crate name used for display purposes,
+    /// without affecting semantics. See the `deps`
+    /// key for semantically-significant crate names.
+    display_name?: string;
+    /// Path to the root module of the crate.
+    root_module: string;
+    /// Edition of the crate.
+    edition: "2015" | "2018" | "2021";
+    /// Dependencies
+    deps: Dep[];
+    /// Should this crate be treated as a member of
+    /// current "workspace".
+    ///
+    /// By default, inferred from the `root_module`
+    /// (members are the crates which reside inside
+    /// the directory opened in the editor).
+    ///
+    /// Set this to `false` for things like standard
+    /// library and 3rd party crates to enable
+    /// performance optimizations (rust-analyzer
+    /// assumes that non-member crates don't change).
+    is_workspace_member?: boolean;
+    /// Optionally specify the (super)set of `.rs`
+    /// files comprising this crate.
+    ///
+    /// By default, rust-analyzer assumes that only
+    /// files under `root_module.parent` can belong
+    /// to a crate. `include_dirs` are included
+    /// recursively, unless a subdirectory is in
+    /// `exclude_dirs`.
+    ///
+    /// Different crates can share the same `source`.
+    ///
+    /// If two crates share an `.rs` file in common,
+    /// they *must* have the same `source`.
+    /// rust-analyzer assumes that files from one
+    /// source can't refer to files in another source.
+    source?: {
+        include_dirs: string[];
+        exclude_dirs: string[];
+    };
+    /// The set of cfgs activated for a given crate, like
+    /// `["unix", "feature=\"foo\"", "feature=\"bar\""]`.
+    cfg: string[];
+    /// Target triple for this Crate.
+    ///
+    /// Used when running `rustc --print cfg`
+    /// to get target-specific cfgs.
+    target?: string;
+    /// Environment variables, used for
+    /// the `env!` macro
+    env: { [key: string]: string };
+
+    /// Whether the crate is a proc-macro crate.
+    is_proc_macro: boolean;
+    /// For proc-macro crates, path to compiled
+    /// proc-macro (.so file).
+    proc_macro_dylib_path?: string;
+}
+
+interface Dep {
+    /// Index of a crate in the `crates` array.
+    crate: number;
+    /// Name as should appear in the (implicit)
+    /// `extern crate name` declaration.
+    name: string;
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/util.ts b/src/tools/rust-analyzer/editors/code/src/util.ts
index d93b9caeb16..922fbcbcf35 100644
--- a/src/tools/rust-analyzer/editors/code/src/util.ts
+++ b/src/tools/rust-analyzer/editors/code/src/util.ts
@@ -150,9 +150,11 @@ export function memoizeAsync<Ret, TThis, Param extends string>(
 
 /** Awaitable wrapper around `child_process.exec` */
 export function execute(command: string, options: ExecOptions): Promise<string> {
+    log.info(`running command: ${command}`);
     return new Promise((resolve, reject) => {
         exec(command, options, (err, stdout, stderr) => {
             if (err) {
+                log.error(err);
                 reject(err);
                 return;
             }
@@ -167,6 +169,21 @@ export function execute(command: string, options: ExecOptions): Promise<string>
     });
 }
 
+export function executeDiscoverProject(command: string, options: ExecOptions): Promise<string> {
+    log.info(`running command: ${command}`);
+    return new Promise((resolve, reject) => {
+        exec(command, options, (err, stdout, _) => {
+            if (err) {
+                log.error(err);
+                reject(err);
+                return;
+            }
+
+            resolve(stdout.trimEnd());
+        });
+    });
+}
+
 export class LazyOutputChannel implements vscode.OutputChannel {
     constructor(name: string) {
         this.name = name;
diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs
index 2ec09d67e3e..abcf59cfe36 100644
--- a/src/tools/rust-installer/src/combiner.rs
+++ b/src/tools/rust-installer/src/combiner.rs
@@ -1,7 +1,7 @@
 use super::Scripter;
 use super::Tarballer;
 use crate::{
-    compression::{CompressionFormat, CompressionFormats},
+    compression::{CompressionFormat, CompressionFormats, CompressionProfile},
     util::*,
 };
 use anyhow::{bail, Context, Result};
@@ -48,6 +48,10 @@ actor! {
         #[clap(value_name = "DIR")]
         output_dir: String = "./dist",
 
+        /// The profile used to compress the tarball.
+        #[clap(value_name = "FORMAT", default_value_t)]
+        compression_profile: CompressionProfile,
+
         /// The formats used to compress the tarball
         #[clap(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
@@ -153,6 +157,7 @@ impl Combiner {
             .work_dir(self.work_dir)
             .input(self.package_name)
             .output(path_to_str(&output)?.into())
+            .compression_profile(self.compression_profile)
             .compression_formats(self.compression_formats.clone());
         tarballer.run()?;
 
diff --git a/src/tools/rust-installer/src/compression.rs b/src/tools/rust-installer/src/compression.rs
index 013e05fda58..510c914163c 100644
--- a/src/tools/rust-installer/src/compression.rs
+++ b/src/tools/rust-installer/src/compression.rs
@@ -4,6 +4,37 @@ use rayon::prelude::*;
 use std::{convert::TryFrom, fmt, io::Read, io::Write, path::Path, str::FromStr};
 use xz2::{read::XzDecoder, write::XzEncoder};
 
+#[derive(Default, Debug, Copy, Clone)]
+pub enum CompressionProfile {
+    Fast,
+    #[default]
+    Balanced,
+    Best,
+}
+
+impl FromStr for CompressionProfile {
+    type Err = Error;
+
+    fn from_str(input: &str) -> Result<Self, Error> {
+        Ok(match input {
+            "fast" => Self::Fast,
+            "balanced" => Self::Balanced,
+            "best" => Self::Best,
+            other => anyhow::bail!("invalid compression profile: {other}"),
+        })
+    }
+}
+
+impl fmt::Display for CompressionProfile {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            CompressionProfile::Fast => f.write_str("fast"),
+            CompressionProfile::Balanced => f.write_str("balanced"),
+            CompressionProfile::Best => f.write_str("best"),
+        }
+    }
+}
+
 #[derive(Debug, Copy, Clone)]
 pub enum CompressionFormat {
     Gz,
@@ -26,7 +57,11 @@ impl CompressionFormat {
         }
     }
 
-    pub(crate) fn encode(&self, path: impl AsRef<Path>) -> Result<Box<dyn Encoder>, Error> {
+    pub(crate) fn encode(
+        &self,
+        path: impl AsRef<Path>,
+        profile: CompressionProfile,
+    ) -> Result<Box<dyn Encoder>, Error> {
         let mut os = path.as_ref().as_os_str().to_os_string();
         os.push(format!(".{}", self.extension()));
         let path = Path::new(&os);
@@ -37,49 +72,64 @@ impl CompressionFormat {
         let file = crate::util::create_new_file(path)?;
 
         Ok(match self {
-            CompressionFormat::Gz => Box::new(GzEncoder::new(file, flate2::Compression::best())),
+            CompressionFormat::Gz => Box::new(GzEncoder::new(
+                file,
+                match profile {
+                    CompressionProfile::Fast => flate2::Compression::fast(),
+                    CompressionProfile::Balanced => flate2::Compression::new(6),
+                    CompressionProfile::Best => flate2::Compression::best(),
+                },
+            )),
             CompressionFormat::Xz => {
-                let mut filters = xz2::stream::Filters::new();
-                // the preset is overridden by the other options so it doesn't matter
-                let mut lzma_ops = xz2::stream::LzmaOptions::new_preset(9).unwrap();
-                // This sets the overall dictionary size, which is also how much memory (baseline)
-                // is needed for decompression.
-                lzma_ops.dict_size(64 * 1024 * 1024);
-                // Use the best match finder for compression ratio.
-                lzma_ops.match_finder(xz2::stream::MatchFinder::BinaryTree4);
-                lzma_ops.mode(xz2::stream::Mode::Normal);
-                // Set nice len to the maximum for best compression ratio
-                lzma_ops.nice_len(273);
-                // Set depth to a reasonable value, 0 means auto, 1000 is somwhat high but gives
-                // good results.
-                lzma_ops.depth(1000);
-                // 2 is the default and does well for most files
-                lzma_ops.position_bits(2);
-                // 0 is the default and does well for most files
-                lzma_ops.literal_position_bits(0);
-                // 3 is the default and does well for most files
-                lzma_ops.literal_context_bits(3);
-
-                filters.lzma2(&lzma_ops);
-
-                let mut builder = xz2::stream::MtStreamBuilder::new();
-                builder.filters(filters);
-
-                // On 32-bit platforms limit ourselves to 3 threads, otherwise we exceed memory
-                // usage this process can take. In the future we'll likely only do super-fast
-                // compression in CI and move this heavyweight processing to promote-release (which
-                // is always 64-bit and can run on big-memory machines) but for now this lets us
-                // move forward.
-                if std::mem::size_of::<usize>() == 4 {
-                    builder.threads(3);
-                } else {
-                    builder.threads(6);
-                }
-
-                let compressor = XzEncoder::new_stream(
-                    std::io::BufWriter::new(file),
-                    builder.encoder().unwrap(),
-                );
+                let encoder = match profile {
+                    CompressionProfile::Fast => {
+                        xz2::stream::MtStreamBuilder::new().threads(6).preset(1).encoder().unwrap()
+                    }
+                    CompressionProfile::Balanced => {
+                        xz2::stream::MtStreamBuilder::new().threads(6).preset(6).encoder().unwrap()
+                    }
+                    CompressionProfile::Best => {
+                        let mut filters = xz2::stream::Filters::new();
+                        // the preset is overridden by the other options so it doesn't matter
+                        let mut lzma_ops = xz2::stream::LzmaOptions::new_preset(9).unwrap();
+                        // This sets the overall dictionary size, which is also how much memory (baseline)
+                        // is needed for decompression.
+                        lzma_ops.dict_size(64 * 1024 * 1024);
+                        // Use the best match finder for compression ratio.
+                        lzma_ops.match_finder(xz2::stream::MatchFinder::BinaryTree4);
+                        lzma_ops.mode(xz2::stream::Mode::Normal);
+                        // Set nice len to the maximum for best compression ratio
+                        lzma_ops.nice_len(273);
+                        // Set depth to a reasonable value, 0 means auto, 1000 is somwhat high but gives
+                        // good results.
+                        lzma_ops.depth(1000);
+                        // 2 is the default and does well for most files
+                        lzma_ops.position_bits(2);
+                        // 0 is the default and does well for most files
+                        lzma_ops.literal_position_bits(0);
+                        // 3 is the default and does well for most files
+                        lzma_ops.literal_context_bits(3);
+
+                        filters.lzma2(&lzma_ops);
+
+                        let mut builder = xz2::stream::MtStreamBuilder::new();
+                        builder.filters(filters);
+
+                        // On 32-bit platforms limit ourselves to 3 threads, otherwise we exceed memory
+                        // usage this process can take. In the future we'll likely only do super-fast
+                        // compression in CI and move this heavyweight processing to promote-release (which
+                        // is always 64-bit and can run on big-memory machines) but for now this lets us
+                        // move forward.
+                        if std::mem::size_of::<usize>() == 4 {
+                            builder.threads(3);
+                        } else {
+                            builder.threads(6);
+                        }
+                        builder.encoder().unwrap()
+                    }
+                };
+
+                let compressor = XzEncoder::new_stream(std::io::BufWriter::new(file), encoder);
                 Box::new(compressor)
             }
         })
diff --git a/src/tools/rust-installer/src/generator.rs b/src/tools/rust-installer/src/generator.rs
index 1e4d00b0553..ddd1052599d 100644
--- a/src/tools/rust-installer/src/generator.rs
+++ b/src/tools/rust-installer/src/generator.rs
@@ -1,6 +1,6 @@
 use super::Scripter;
 use super::Tarballer;
-use crate::compression::CompressionFormats;
+use crate::compression::{CompressionFormats, CompressionProfile};
 use crate::util::*;
 use anyhow::{bail, format_err, Context, Result};
 use std::collections::BTreeSet;
@@ -54,6 +54,10 @@ actor! {
         #[clap(value_name = "DIR")]
         output_dir: String = "./dist",
 
+        /// The profile used to compress the tarball.
+        #[clap(value_name = "FORMAT", default_value_t)]
+        compression_profile: CompressionProfile,
+
         /// The formats used to compress the tarball
         #[clap(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
@@ -113,6 +117,7 @@ impl Generator {
             .work_dir(self.work_dir)
             .input(self.package_name)
             .output(path_to_str(&output)?.into())
+            .compression_profile(self.compression_profile)
             .compression_formats(self.compression_formats.clone());
         tarballer.run()?;
 
diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs
index 76f5af3fa53..592eba8f698 100644
--- a/src/tools/rust-installer/src/tarballer.rs
+++ b/src/tools/rust-installer/src/tarballer.rs
@@ -6,7 +6,7 @@ use tar::{Builder, Header};
 use walkdir::WalkDir;
 
 use crate::{
-    compression::{CombinedEncoder, CompressionFormats},
+    compression::{CombinedEncoder, CompressionFormats, CompressionProfile},
     util::*,
 };
 
@@ -25,6 +25,10 @@ actor! {
         #[clap(value_name = "DIR")]
         work_dir: String = "./workdir",
 
+        /// The profile used to compress the tarball.
+        #[clap(value_name = "FORMAT", default_value_t)]
+        compression_profile: CompressionProfile,
+
         /// The formats used to compress the tarball.
         #[clap(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
@@ -38,7 +42,7 @@ impl Tarballer {
         let encoder = CombinedEncoder::new(
             self.compression_formats
                 .iter()
-                .map(|f| f.encode(&tarball_name))
+                .map(|f| f.encode(&tarball_name, self.compression_profile))
                 .collect::<Result<Vec<_>>>()?,
         );
 
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index b296aa2f4e6..8286bd506bc 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -9,6 +9,6 @@ clap = "4.0.32"
 env_logger = "0.7.1"
 
 [dependencies.mdbook]
-version = "0.4.25"
+version = "0.4.28"
 default-features = false
 features = ["search"]
diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs
index 2d6abe59343..070ce93f97c 100644
--- a/src/tools/tidy/src/bins.rs
+++ b/src/tools/tidy/src/bins.rs
@@ -103,7 +103,7 @@ mod os_impl {
 
         // FIXME: we don't need to look at all binaries, only files that have been modified in this branch
         // (e.g. using `git ls-files`).
-        walk_no_read(path, |path| filter_dirs(path) || path.ends_with("src/etc"), &mut |entry| {
+        walk_no_read(&[path], |path| filter_dirs(path) || path.ends_with("src/etc"), &mut |entry| {
             let file = entry.path();
             let extension = file.extension();
             let scripts = ["py", "sh", "ps1"];
diff --git a/src/tools/tidy/src/debug_artifacts.rs b/src/tools/tidy/src/debug_artifacts.rs
index 2241375eaae..84b13306805 100644
--- a/src/tools/tidy/src/debug_artifacts.rs
+++ b/src/tools/tidy/src/debug_artifacts.rs
@@ -1,21 +1,15 @@
 //! Tidy check to prevent creation of unnecessary debug artifacts while running tests.
 
-use crate::walk::{filter_dirs, walk};
+use crate::walk::{filter_dirs, filter_not_rust, walk};
 use std::path::Path;
 
 const GRAPHVIZ_POSTFLOW_MSG: &str = "`borrowck_graphviz_postflow` attribute in test";
 
 pub fn check(test_dir: &Path, bad: &mut bool) {
-    walk(test_dir, filter_dirs, &mut |entry, contents| {
-        let filename = entry.path();
-        let is_rust = filename.extension().map_or(false, |ext| ext == "rs");
-        if !is_rust {
-            return;
-        }
-
+    walk(test_dir, |path| filter_dirs(path) || filter_not_rust(path), &mut |entry, contents| {
         for (i, line) in contents.lines().enumerate() {
             if line.contains("borrowck_graphviz_postflow") {
-                tidy_error!(bad, "{}:{}: {}", filename.display(), i + 1, GRAPHVIZ_POSTFLOW_MSG);
+                tidy_error!(bad, "{}:{}: {}", entry.path().display(), i + 1, GRAPHVIZ_POSTFLOW_MSG);
             }
         }
     });
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index d71fa5c8be5..a9eb6c8d03f 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -260,6 +260,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "valuable",
     "version_check",
     "wasi",
+    "windows",
     "winapi",
     "winapi-i686-pc-windows-gnu",
     "winapi-util",
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 6d94417a10f..f18feda533c 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -9,8 +9,9 @@
 //! * All unstable lang features have tests to ensure they are actually unstable.
 //! * Language features in a group are sorted by feature name.
 
-use crate::walk::{filter_dirs, walk, walk_many};
+use crate::walk::{filter_dirs, filter_not_rust, walk, walk_many};
 use std::collections::hash_map::{Entry, HashMap};
+use std::ffi::OsStr;
 use std::fmt;
 use std::fs;
 use std::num::NonZeroU32;
@@ -101,17 +102,15 @@ pub fn check(
             &tests_path.join("rustdoc-ui"),
             &tests_path.join("rustdoc"),
         ],
-        filter_dirs,
+        |path| {
+            filter_dirs(path)
+                || filter_not_rust(path)
+                || path.file_name() == Some(OsStr::new("features.rs"))
+                || path.file_name() == Some(OsStr::new("diagnostic_list.rs"))
+        },
         &mut |entry, contents| {
             let file = entry.path();
             let filename = file.file_name().unwrap().to_string_lossy();
-            if !filename.ends_with(".rs")
-                || filename == "features.rs"
-                || filename == "diagnostic_list.rs"
-            {
-                return;
-            }
-
             let filen_underscore = filename.replace('-', "_").replace(".rs", "");
             let filename_is_gate_test = test_filen_gate(&filen_underscore, &mut features);
 
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index d98758ace4f..f59406c404b 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -13,7 +13,7 @@ use std::path::PathBuf;
 use std::process;
 use std::str::FromStr;
 use std::sync::atomic::{AtomicBool, Ordering};
-use std::thread::{scope, ScopedJoinHandle};
+use std::thread::{self, scope, ScopedJoinHandle};
 
 fn main() {
     let root_path: PathBuf = env::args_os().nth(1).expect("need path to root of repo").into();
@@ -55,16 +55,28 @@ fn main() {
             VecDeque::with_capacity(concurrency.get());
 
         macro_rules! check {
-            ($p:ident $(, $args:expr)* ) => {
+            ($p:ident) => {
+                check!(@ $p, name=format!("{}", stringify!($p)));
+            };
+            ($p:ident, $path:expr $(, $args:expr)* ) => {
+                let shortened = $path.strip_prefix(&root_path).unwrap();
+                let name = if shortened == std::path::Path::new("") {
+                    format!("{} (.)", stringify!($p))
+                } else {
+                    format!("{} ({})", stringify!($p), shortened.display())
+                };
+                check!(@ $p, name=name, $path $(,$args)*);
+            };
+            (@ $p:ident, name=$name:expr $(, $args:expr)* ) => {
                 drain_handles(&mut handles);
 
-                let handle = s.spawn(|| {
+                let handle = thread::Builder::new().name($name).spawn_scoped(s, || {
                     let mut flag = false;
                     $p::check($($args, )* &mut flag);
                     if (flag) {
                         bad.store(true, Ordering::Relaxed);
                     }
-                });
+                }).unwrap();
                 handles.push_back(handle);
             }
         }
@@ -108,7 +120,6 @@ fn main() {
         check!(edition, &library_path);
 
         check!(alphabetical, &src_path);
-        check!(alphabetical, &tests_path);
         check!(alphabetical, &compiler_path);
         check!(alphabetical, &library_path);
 
diff --git a/src/tools/tidy/src/mir_opt_tests.rs b/src/tools/tidy/src/mir_opt_tests.rs
index 2a9dcac2e8d..b316e9e9009 100644
--- a/src/tools/tidy/src/mir_opt_tests.rs
+++ b/src/tools/tidy/src/mir_opt_tests.rs
@@ -3,19 +3,24 @@
 use std::collections::HashSet;
 use std::path::{Path, PathBuf};
 
+use crate::walk::walk_no_read;
+
 fn check_unused_files(path: &Path, bless: bool, bad: &mut bool) {
     let mut rs_files = Vec::<PathBuf>::new();
     let mut output_files = HashSet::<PathBuf>::new();
-    let files = walkdir::WalkDir::new(&path.join("mir-opt")).into_iter();
 
-    for file in files.filter_map(Result::ok).filter(|e| e.file_type().is_file()) {
-        let filepath = file.path();
-        if filepath.extension() == Some("rs".as_ref()) {
-            rs_files.push(filepath.to_owned());
-        } else {
-            output_files.insert(filepath.to_owned());
-        }
-    }
+    walk_no_read(
+        &[&path.join("mir-opt")],
+        |path| path.file_name() == Some("README.md".as_ref()),
+        &mut |file| {
+            let filepath = file.path();
+            if filepath.extension() == Some("rs".as_ref()) {
+                rs_files.push(filepath.to_owned());
+            } else {
+                output_files.insert(filepath.to_owned());
+            }
+        },
+    );
 
     for file in rs_files {
         for bw in [32, 64] {
@@ -26,16 +31,14 @@ fn check_unused_files(path: &Path, bless: bool, bad: &mut bool) {
     }
 
     for extra in output_files {
-        if extra.file_name() != Some("README.md".as_ref()) {
-            if !bless {
-                tidy_error!(
-                    bad,
-                    "the following output file is not associated with any mir-opt test, you can remove it: {}",
-                    extra.display()
-                );
-            } else {
-                let _ = std::fs::remove_file(extra);
-            }
+        if !bless {
+            tidy_error!(
+                bad,
+                "the following output file is not associated with any mir-opt test, you can remove it: {}",
+                extra.display()
+            );
+        } else {
+            let _ = std::fs::remove_file(extra);
         }
     }
 }
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index 868579b4b1a..6b7b27fd526 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -59,7 +59,6 @@ const EXCEPTION_PATHS: &[&str] = &[
     "library/std/src/path.rs",
     "library/std/src/sys_common", // Should only contain abstractions over platforms
     "library/std/src/net/test.rs", // Utility helpers for tests
-    "library/std/src/panic.rs",   // fuchsia-specific panic backtrace handling
     "library/std/src/personality.rs",
     "library/std/src/personality/",
 ];
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 75a4586cb7f..a965c98f484 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -19,7 +19,7 @@
 
 use crate::walk::{filter_dirs, walk};
 use regex::{Regex, RegexSet};
-use std::path::Path;
+use std::{ffi::OsStr, path::Path};
 
 /// Error code markdown is restricted to 80 columns because they can be
 /// displayed on the console with --example.
@@ -228,21 +228,33 @@ fn is_unexplained_ignore(extension: &str, line: &str) -> bool {
 
 pub fn check(path: &Path, bad: &mut bool) {
     fn skip(path: &Path) -> bool {
-        filter_dirs(path) || skip_markdown_path(path)
+        if path.file_name().map_or(false, |name| name.to_string_lossy().starts_with(".#")) {
+            // vim or emacs temporary file
+            return true;
+        }
+
+        if filter_dirs(path) || skip_markdown_path(path) {
+            return true;
+        }
+
+        let extensions = ["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "goml"];
+        if extensions.iter().all(|e| path.extension() != Some(OsStr::new(e))) {
+            return true;
+        }
+
+        // We only check CSS files in rustdoc.
+        path.extension().map_or(false, |e| e == "css") && !is_in(path, "src", "librustdoc")
     }
+
     let problematic_consts_strings: Vec<String> = (PROBLEMATIC_CONSTS.iter().map(u32::to_string))
         .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:x}", v)))
         .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:X}", v)))
         .collect();
     let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap();
+
     walk(path, skip, &mut |entry, contents| {
         let file = entry.path();
         let filename = file.file_name().unwrap().to_string_lossy();
-        let extensions =
-            [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h", ".md", ".css", ".ftl", ".goml"];
-        if extensions.iter().all(|e| !filename.ends_with(e)) || filename.starts_with(".#") {
-            return;
-        }
 
         let is_style_file = filename.ends_with(".css");
         let under_rustfmt = filename.ends_with(".rs") &&
@@ -253,11 +265,6 @@ pub fn check(path: &Path, bad: &mut bool) {
                     a.ends_with("src/doc/book")
             });
 
-        if is_style_file && !is_in(file, "src", "librustdoc") {
-            // We only check CSS files in rustdoc.
-            return;
-        }
-
         if contents.is_empty() {
             tidy_error!(bad, "{}: empty file", file.display());
         }
diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs
index f41fa4fcce1..e0fa6aceb85 100644
--- a/src/tools/tidy/src/target_specific_tests.rs
+++ b/src/tools/tidy/src/target_specific_tests.rs
@@ -4,6 +4,8 @@
 use std::collections::BTreeMap;
 use std::path::Path;
 
+use crate::walk::filter_not_rust;
+
 const COMMENT: &str = "//";
 const LLVM_COMPONENTS_HEADER: &str = "needs-llvm-components:";
 const COMPILE_FLAGS_HEADER: &str = "compile-flags:";
@@ -35,61 +37,57 @@ struct RevisionInfo<'a> {
 }
 
 pub fn check(path: &Path, bad: &mut bool) {
-    crate::walk::walk(
-        path,
-        |path| path.extension().map(|p| p == "rs") == Some(false),
-        &mut |entry, content| {
-            let file = entry.path().display();
-            let mut header_map = BTreeMap::new();
-            iter_header(content, &mut |cfg, directive| {
-                if let Some(value) = directive.strip_prefix(LLVM_COMPONENTS_HEADER) {
-                    let info = header_map.entry(cfg).or_insert(RevisionInfo::default());
-                    let comp_vec = info.llvm_components.get_or_insert(Vec::new());
-                    for component in value.split(' ') {
-                        let component = component.trim();
-                        if !component.is_empty() {
-                            comp_vec.push(component);
-                        }
-                    }
-                } else if directive.starts_with(COMPILE_FLAGS_HEADER) {
-                    let compile_flags = &directive[COMPILE_FLAGS_HEADER.len()..];
-                    if let Some((_, v)) = compile_flags.split_once("--target") {
-                        if let Some((arch, _)) =
-                            v.trim_start_matches(|c| c == ' ' || c == '=').split_once("-")
-                        {
-                            let info = header_map.entry(cfg).or_insert(RevisionInfo::default());
-                            info.target_arch.replace(arch);
-                        } else {
-                            eprintln!("{file}: seems to have a malformed --target value");
-                            *bad = true;
-                        }
+    crate::walk::walk(path, filter_not_rust, &mut |entry, content| {
+        let file = entry.path().display();
+        let mut header_map = BTreeMap::new();
+        iter_header(content, &mut |cfg, directive| {
+            if let Some(value) = directive.strip_prefix(LLVM_COMPONENTS_HEADER) {
+                let info = header_map.entry(cfg).or_insert(RevisionInfo::default());
+                let comp_vec = info.llvm_components.get_or_insert(Vec::new());
+                for component in value.split(' ') {
+                    let component = component.trim();
+                    if !component.is_empty() {
+                        comp_vec.push(component);
                     }
                 }
-            });
-            for (rev, RevisionInfo { target_arch, llvm_components }) in &header_map {
-                let rev = rev.unwrap_or("[unspecified]");
-                match (target_arch, llvm_components) {
-                    (None, None) => {}
-                    (Some(_), None) => {
-                        eprintln!(
-                            "{}: revision {} should specify `{}` as it has `--target` set",
-                            file, rev, LLVM_COMPONENTS_HEADER
-                        );
+            } else if directive.starts_with(COMPILE_FLAGS_HEADER) {
+                let compile_flags = &directive[COMPILE_FLAGS_HEADER.len()..];
+                if let Some((_, v)) = compile_flags.split_once("--target") {
+                    if let Some((arch, _)) =
+                        v.trim_start_matches(|c| c == ' ' || c == '=').split_once("-")
+                    {
+                        let info = header_map.entry(cfg).or_insert(RevisionInfo::default());
+                        info.target_arch.replace(arch);
+                    } else {
+                        eprintln!("{file}: seems to have a malformed --target value");
                         *bad = true;
                     }
-                    (None, Some(_)) => {
-                        eprintln!(
-                            "{}: revision {} should not specify `{}` as it doesn't need `--target`",
-                            file, rev, LLVM_COMPONENTS_HEADER
-                        );
-                        *bad = true;
-                    }
-                    (Some(_), Some(_)) => {
-                        // FIXME: check specified components against the target architectures we
-                        // gathered.
-                    }
                 }
             }
-        },
-    );
+        });
+        for (rev, RevisionInfo { target_arch, llvm_components }) in &header_map {
+            let rev = rev.unwrap_or("[unspecified]");
+            match (target_arch, llvm_components) {
+                (None, None) => {}
+                (Some(_), None) => {
+                    eprintln!(
+                        "{}: revision {} should specify `{}` as it has `--target` set",
+                        file, rev, LLVM_COMPONENTS_HEADER
+                    );
+                    *bad = true;
+                }
+                (None, Some(_)) => {
+                    eprintln!(
+                        "{}: revision {} should not specify `{}` as it doesn't need `--target`",
+                        file, rev, LLVM_COMPONENTS_HEADER
+                    );
+                    *bad = true;
+                }
+                (Some(_), Some(_)) => {
+                    // FIXME: check specified components against the target architectures we
+                    // gathered.
+                }
+            }
+        }
+    });
 }
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 15c36923e88..66f5c932be2 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -3,87 +3,83 @@
 //! - there are no stray `.stderr` files
 
 use ignore::Walk;
-use ignore::WalkBuilder;
+use std::collections::HashMap;
 use std::fs;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
 const ROOT_ENTRY_LIMIT: usize = 940;
 const ISSUES_ENTRY_LIMIT: usize = 1978;
 
-fn check_entries(path: &Path, bad: &mut bool) {
-    for dir in Walk::new(&path.join("ui")) {
+fn check_entries(tests_path: &Path, bad: &mut bool) {
+    let mut directories: HashMap<PathBuf, usize> = HashMap::new();
+
+    for dir in Walk::new(&tests_path.join("ui")) {
         if let Ok(entry) = dir {
-            if entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) {
-                let dir_path = entry.path();
-                // Use special values for these dirs.
-                let is_root = path.join("ui") == dir_path;
-                let is_issues_dir = path.join("ui/issues") == dir_path;
-                let limit = if is_root {
-                    ROOT_ENTRY_LIMIT
-                } else if is_issues_dir {
-                    ISSUES_ENTRY_LIMIT
-                } else {
-                    ENTRY_LIMIT
-                };
+            let parent = entry.path().parent().unwrap().to_path_buf();
+            *directories.entry(parent).or_default() += 1;
+        }
+    }
 
-                let count = WalkBuilder::new(&dir_path)
-                    .max_depth(Some(1))
-                    .build()
-                    .into_iter()
-                    .collect::<Vec<_>>()
-                    .len()
-                    - 1; // remove the dir itself
+    for (dir_path, count) in directories {
+        // Use special values for these dirs.
+        let is_root = tests_path.join("ui") == dir_path;
+        let is_issues_dir = tests_path.join("ui/issues") == dir_path;
+        let limit = if is_root {
+            ROOT_ENTRY_LIMIT
+        } else if is_issues_dir {
+            ISSUES_ENTRY_LIMIT
+        } else {
+            ENTRY_LIMIT
+        };
 
-                if count > limit {
-                    tidy_error!(
-                        bad,
-                        "following path contains more than {} entries, \
-                            you should move the test to some relevant subdirectory (current: {}): {}",
-                        limit,
-                        count,
-                        dir_path.display()
-                    );
-                }
-            }
+        if count > limit {
+            tidy_error!(
+                bad,
+                "following path contains more than {} entries, \
+                    you should move the test to some relevant subdirectory (current: {}): {}",
+                limit,
+                count,
+                dir_path.display()
+            );
         }
     }
 }
 
 pub fn check(path: &Path, bad: &mut bool) {
     check_entries(&path, bad);
-    for path in &[&path.join("ui"), &path.join("ui-fulldeps")] {
-        crate::walk::walk_no_read(path, |_| false, &mut |entry| {
-            let file_path = entry.path();
-            if let Some(ext) = file_path.extension() {
-                if ext == "stderr" || ext == "stdout" {
-                    // Test output filenames have one of the formats:
-                    // ```
-                    // $testname.stderr
-                    // $testname.$mode.stderr
-                    // $testname.$revision.stderr
-                    // $testname.$revision.$mode.stderr
-                    // ```
-                    //
-                    // For now, just make sure that there is a corresponding
-                    // `$testname.rs` file.
-                    //
-                    // NB: We do not use file_stem() as some file names have multiple `.`s and we
-                    // must strip all of them.
-                    let testname =
-                        file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0;
-                    if !file_path.with_file_name(testname).with_extension("rs").exists() {
-                        tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path);
-                    }
+    let (ui, ui_fulldeps) = (path.join("ui"), path.join("ui-fulldeps"));
+    let paths = [ui.as_path(), ui_fulldeps.as_path()];
+    crate::walk::walk_no_read(&paths, |_| false, &mut |entry| {
+        let file_path = entry.path();
+        if let Some(ext) = file_path.extension() {
+            if ext == "stderr" || ext == "stdout" {
+                // Test output filenames have one of the formats:
+                // ```
+                // $testname.stderr
+                // $testname.$mode.stderr
+                // $testname.$revision.stderr
+                // $testname.$revision.$mode.stderr
+                // ```
+                //
+                // For now, just make sure that there is a corresponding
+                // `$testname.rs` file.
+                //
+                // NB: We do not use file_stem() as some file names have multiple `.`s and we
+                // must strip all of them.
+                let testname =
+                    file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0;
+                if !file_path.with_file_name(testname).with_extension("rs").exists() {
+                    tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path);
+                }
 
-                    if let Ok(metadata) = fs::metadata(file_path) {
-                        if metadata.len() == 0 {
-                            tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path);
-                        }
+                if let Ok(metadata) = fs::metadata(file_path) {
+                    if metadata.len() == 0 {
+                        tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path);
                     }
                 }
             }
-        });
-    }
+        }
+    });
 }
diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs
index 94152e75168..2ade22c209f 100644
--- a/src/tools/tidy/src/walk.rs
+++ b/src/tools/tidy/src/walk.rs
@@ -1,6 +1,6 @@
 use ignore::DirEntry;
 
-use std::{fs::File, io::Read, path::Path};
+use std::{ffi::OsStr, fs::File, io::Read, path::Path};
 
 /// The default directory filter.
 pub fn filter_dirs(path: &Path) -> bool {
@@ -33,23 +33,26 @@ pub fn filter_dirs(path: &Path) -> bool {
     skip.iter().any(|p| path.ends_with(p))
 }
 
-pub fn walk_many(
-    paths: &[&Path],
+/// Filter for only files that end in `.rs`.
+pub fn filter_not_rust(path: &Path) -> bool {
+    path.extension() != Some(OsStr::new("rs")) && !path.is_dir()
+}
+
+pub fn walk(
+    path: &Path,
     skip: impl Clone + Send + Sync + 'static + Fn(&Path) -> bool,
     f: &mut dyn FnMut(&DirEntry, &str),
 ) {
-    for path in paths {
-        walk(path, skip.clone(), f);
-    }
+    walk_many(&[path], skip, f);
 }
 
-pub fn walk(
-    path: &Path,
-    skip: impl Send + Sync + 'static + Fn(&Path) -> bool,
+pub fn walk_many(
+    paths: &[&Path],
+    skip: impl Clone + Send + Sync + 'static + Fn(&Path) -> bool,
     f: &mut dyn FnMut(&DirEntry, &str),
 ) {
     let mut contents = Vec::new();
-    walk_no_read(path, skip, &mut |entry| {
+    walk_no_read(paths, skip, &mut |entry| {
         contents.clear();
         let mut file = t!(File::open(entry.path()), entry.path());
         t!(file.read_to_end(&mut contents), entry.path());
@@ -62,11 +65,14 @@ pub fn walk(
 }
 
 pub(crate) fn walk_no_read(
-    path: &Path,
+    paths: &[&Path],
     skip: impl Send + Sync + 'static + Fn(&Path) -> bool,
     f: &mut dyn FnMut(&DirEntry),
 ) {
-    let mut walker = ignore::WalkBuilder::new(path);
+    let mut walker = ignore::WalkBuilder::new(paths[0]);
+    for path in &paths[1..] {
+        walker.add(path);
+    }
     let walker = walker.filter_entry(move |e| !skip(e.path()));
     for entry in walker.build() {
         if let Ok(entry) = entry {
diff --git a/tests/codegen-units/polymorphization/auxiliary/poly-dep.rs b/tests/codegen-units/polymorphization/auxiliary/poly-dep.rs
new file mode 100644
index 00000000000..fdbfa1b096d
--- /dev/null
+++ b/tests/codegen-units/polymorphization/auxiliary/poly-dep.rs
@@ -0,0 +1,4 @@
+// compile-flags: -Zpolymorphize=on
+
+#[inline(never)]
+pub fn foo<T>() {}
diff --git a/tests/codegen-units/polymorphization/poly-foreign.rs b/tests/codegen-units/polymorphization/poly-foreign.rs
new file mode 100644
index 00000000000..9da082daf11
--- /dev/null
+++ b/tests/codegen-units/polymorphization/poly-foreign.rs
@@ -0,0 +1,11 @@
+// aux-build:poly-dep.rs
+// compile-flags: --crate-type=lib -Zprint-mono-items=eager -Zpolymorphize=on
+
+extern crate poly_dep;
+
+pub static FN1: fn() = poly_dep::foo::<i32>;
+pub static FN2: fn() = poly_dep::foo::<u32>;
+
+//~ MONO_ITEM static FN1
+//~ MONO_ITEM static FN2
+//~ MONO_ITEM fn poly_dep::foo::<T>
diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs
index ac8cba06b48..7f383a5c149 100644
--- a/tests/codegen/fewer-names.rs
+++ b/tests/codegen/fewer-names.rs
@@ -13,8 +13,8 @@ pub fn sum(x: u32, y: u32) -> u32 {
 
 // NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y)
 // NO-NEXT:  start:
-// NO-NEXT:    %z = add i32 %y, %x
-// NO-NEXT:    ret i32 %z
+// NO-NEXT:    %0 = add i32 %y, %x
+// NO-NEXT:    ret i32 %0
     let z = x + y;
     z
 }
diff --git a/tests/codegen/inherit_overflow.rs b/tests/codegen/inherit_overflow.rs
index 0b0b890b2c9..39909d7abfd 100644
--- a/tests/codegen/inherit_overflow.rs
+++ b/tests/codegen/inherit_overflow.rs
@@ -4,7 +4,7 @@
 //[NOASSERT] compile-flags: -Coverflow-checks=off
 
 // CHECK-LABEL: define{{.*}} @assertion
-// ASSERT: call void @_ZN4core9panicking5panic17h
+// ASSERT: call void @{{.*4core9panicking5panic}}
 // NOASSERT: ret i8 0
 #[no_mangle]
 pub fn assertion() -> u8 {
diff --git a/tests/codegen/issues/issue-106369.rs b/tests/codegen/issues/issue-106369.rs
new file mode 100644
index 00000000000..3fe7be4f144
--- /dev/null
+++ b/tests/codegen/issues/issue-106369.rs
@@ -0,0 +1,15 @@
+// compile-flags: -O
+// ignore-debug (the extra assertions get in the way)
+
+#![crate_type = "lib"]
+
+// From <https://github.com/rust-lang/rust/issues/106369#issuecomment-1369095304>
+
+// CHECK-LABEL: @issue_106369(
+#[no_mangle]
+pub unsafe fn issue_106369(ptr: *const &i32) -> bool {
+    // CHECK-NOT: icmp
+    // CHECK: ret i1 true
+    // CHECK-NOT: icmp
+    Some(std::ptr::read(ptr)).is_some()
+}
diff --git a/tests/codegen/issues/issue-73258.rs b/tests/codegen/issues/issue-73258.rs
new file mode 100644
index 00000000000..0134f929b29
--- /dev/null
+++ b/tests/codegen/issues/issue-73258.rs
@@ -0,0 +1,38 @@
+// compile-flags: -O
+// ignore-debug (the extra assertions get in the way)
+
+#![crate_type = "lib"]
+
+// Adapted from <https://github.com/rust-lang/rust/issues/73258#issue-637346014>
+
+#[derive(Clone, Copy)]
+#[repr(u8)]
+pub enum Foo {
+    A, B, C, D,
+}
+
+// CHECK-LABEL: @issue_73258(
+#[no_mangle]
+pub unsafe fn issue_73258(ptr: *const Foo) -> Foo {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: call
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+
+    // CHECK: %[[R:.+]] = load i8
+    // CHECK-SAME: !range !
+
+    // CHECK-NOT: icmp
+    // CHECK-NOT: call
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+
+    // CHECK: ret i8 %[[R]]
+
+    // CHECK-NOT: icmp
+    // CHECK-NOT: call
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+    let k: Option<Foo> = Some(ptr.read());
+    return k.unwrap();
+}
diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs
new file mode 100644
index 00000000000..f6898e2f758
--- /dev/null
+++ b/tests/codegen/mem-replace-big-type.rs
@@ -0,0 +1,36 @@
+// This test ensures that `mem::replace::<T>` only ever calls `@llvm.memcpy`
+// with `size_of::<T>()` as the size, and never goes through any wrapper that
+// may e.g. multiply `size_of::<T>()` with a variable "count" (which is only
+// known to be `1` after inlining).
+
+// compile-flags: -C no-prepopulate-passes -Zinline-mir=no
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+
+#[repr(C, align(8))]
+pub struct Big([u64; 7]);
+pub fn replace_big(dst: &mut Big, src: Big) -> Big {
+    // Before the `read_via_copy` intrinsic, this emitted six `memcpy`s.
+    std::mem::replace(dst, src)
+}
+
+// NOTE(eddyb) the `CHECK-NOT`s ensure that the only calls of `@llvm.memcpy` in
+// the entire output, are the direct calls we want, from `ptr::replace`.
+
+// CHECK-NOT: call void @llvm.memcpy
+
+// For a large type, we expect exactly three `memcpy`s
+// CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}sret(%Big)
+    // CHECK-NOT: alloca
+    // CHECK: alloca %Big
+    // CHECK-NOT: alloca
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %{{.*}}, {{i8\*|ptr}} align 8 %{{.*}}, i{{.*}} 56, i1 false)
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %{{.*}}, {{i8\*|ptr}} align 8 %{{.*}}, i{{.*}} 56, i1 false)
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %{{.*}}, {{i8\*|ptr}} align 8 %{{.*}}, i{{.*}} 56, i1 false)
+    // CHECK-NOT: call void @llvm.memcpy
+
+// CHECK-NOT: call void @llvm.memcpy
diff --git a/tests/codegen/mem-replace-direct-memcpy.rs b/tests/codegen/mem-replace-direct-memcpy.rs
index e8bbf0e1bbd..83babab4f84 100644
--- a/tests/codegen/mem-replace-direct-memcpy.rs
+++ b/tests/codegen/mem-replace-direct-memcpy.rs
@@ -13,12 +13,21 @@ pub fn replace_byte(dst: &mut u8, src: u8) -> u8 {
 }
 
 // NOTE(eddyb) the `CHECK-NOT`s ensure that the only calls of `@llvm.memcpy` in
-// the entire output, are the two direct calls we want, from `ptr::replace`.
+// the entire output, are the direct calls we want, from `ptr::replace`.
 
 // CHECK-NOT: call void @llvm.memcpy
-// CHECK: ; core::mem::replace
-// CHECK-NOT: call void @llvm.memcpy
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, i{{.*}} 1, i1 false)
-// CHECK-NOT: call void @llvm.memcpy
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, i{{.*}} 1, i1 false)
+
+// For a small type, we expect one each of `load`/`store`/`memcpy` instead
+// CHECK-LABEL: define internal noundef i8 @{{.+}}mem{{.+}}replace
+    // CHECK-NOT: alloca
+    // CHECK: alloca i8
+    // CHECK-NOT: alloca
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: load i8
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: store i8
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, i{{.*}} 1, i1 false)
+    // CHECK-NOT: call void @llvm.memcpy
+
 // CHECK-NOT: call void @llvm.memcpy
diff --git a/tests/codegen/ptr-read-metadata.rs b/tests/codegen/ptr-read-metadata.rs
new file mode 100644
index 00000000000..e1e3272662c
--- /dev/null
+++ b/tests/codegen/ptr-read-metadata.rs
@@ -0,0 +1,96 @@
+// compile-flags: -O -Z merge-functions=disabled
+// no-system-llvm
+// ignore-debug (the extra assertions get in the way)
+
+#![crate_type = "lib"]
+
+// Ensure that various forms of reading pointers correctly annotate the `load`s
+// with `!noundef` and `!range` metadata to enable extra optimization.
+
+use std::mem::MaybeUninit;
+
+// CHECK-LABEL: define noundef i8 @copy_byte(
+#[no_mangle]
+pub unsafe fn copy_byte(p: *const u8) -> u8 {
+    // CHECK-NOT: load
+    // CHECK: load i8, ptr %p, align 1
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    *p
+}
+
+// CHECK-LABEL: define noundef i8 @read_byte(
+#[no_mangle]
+pub unsafe fn read_byte(p: *const u8) -> u8 {
+    // CHECK-NOT: load
+    // CHECK: load i8, ptr %p, align 1
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    p.read()
+}
+
+// CHECK-LABEL: define i8 @read_byte_maybe_uninit(
+#[no_mangle]
+pub unsafe fn read_byte_maybe_uninit(p: *const MaybeUninit<u8>) -> MaybeUninit<u8> {
+    // CHECK-NOT: load
+    // CHECK: load i8, ptr %p, align 1
+    // CHECK-NOT: noundef
+    // CHECK-NOT: load
+    p.read()
+}
+
+// CHECK-LABEL: define noundef i8 @read_byte_assume_init(
+#[no_mangle]
+pub unsafe fn read_byte_assume_init(p: &MaybeUninit<u8>) -> u8 {
+    // CHECK-NOT: load
+    // CHECK: load i8, ptr %p, align 1
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    p.assume_init_read()
+}
+
+// CHECK-LABEL: define noundef i32 @copy_char(
+#[no_mangle]
+pub unsafe fn copy_char(p: *const char) -> char {
+    // CHECK-NOT: load
+    // CHECK: load i32, ptr %p
+    // CHECK-SAME: !range ![[RANGE:[0-9]+]]
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    *p
+}
+
+// CHECK-LABEL: define noundef i32 @read_char(
+#[no_mangle]
+pub unsafe fn read_char(p: *const char) -> char {
+    // CHECK-NOT: load
+    // CHECK: load i32, ptr %p
+    // CHECK-SAME: !range ![[RANGE]]
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    p.read()
+}
+
+// CHECK-LABEL: define i32 @read_char_maybe_uninit(
+#[no_mangle]
+pub unsafe fn read_char_maybe_uninit(p: *const MaybeUninit<char>) -> MaybeUninit<char> {
+    // CHECK-NOT: load
+    // CHECK: load i32, ptr %p
+    // CHECK-NOT: range
+    // CHECK-NOT: noundef
+    // CHECK-NOT: load
+    p.read()
+}
+
+// CHECK-LABEL: define noundef i32 @read_char_assume_init(
+#[no_mangle]
+pub unsafe fn read_char_assume_init(p: &MaybeUninit<char>) -> char {
+    // CHECK-NOT: load
+    // CHECK: load i32, ptr %p
+    // CHECK-SAME: !range ![[RANGE]]
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    p.assume_init_read()
+}
+
+// CHECK: ![[RANGE]] = !{i32 0, i32 1114112}
diff --git a/tests/codegen/var-names.rs b/tests/codegen/var-names.rs
index d4715efad73..53841df32e8 100644
--- a/tests/codegen/var-names.rs
+++ b/tests/codegen/var-names.rs
@@ -9,7 +9,7 @@ pub fn test(a: u32, b: u32) -> u32 {
     // CHECK: %c = add i32 %a, %b
     let d = c;
     let e = d * a;
-    // CHECK-NEXT: %e = mul i32 %c, %a
+    // CHECK-NEXT: %0 = mul i32 %c, %a
     e
-    // CHECK-NEXT: ret i32 %e
+    // CHECK-NEXT: ret i32 %0
 }
diff --git a/tests/codegen/vec-as-ptr.rs b/tests/codegen/vec-as-ptr.rs
new file mode 100644
index 00000000000..8ff7ba9cb64
--- /dev/null
+++ b/tests/codegen/vec-as-ptr.rs
@@ -0,0 +1,19 @@
+// compile-flags: -O -Zmerge-functions=disabled
+
+#![crate_type = "lib"]
+
+// Test that even though we return a *const u8 not a &[u8] or a NonNull<u8>, LLVM knows that this
+// pointer is nonnull.
+// CHECK: nonnull {{i8\*|ptr}} @vec_as_ptr
+#[no_mangle]
+pub fn vec_as_ptr(v: &Vec<u8>) -> *const u8 {
+    v.as_ptr()
+}
+
+// Test that even though we return a *const u8 not a &[u8] or a NonNull<u8>, LLVM knows that this
+// pointer is nonnull.
+// CHECK: nonnull {{i8\*|ptr}} @vec_as_mut_ptr
+#[no_mangle]
+pub fn vec_as_mut_ptr(v: &mut Vec<u8>) -> *mut u8 {
+    v.as_mut_ptr()
+}
diff --git a/tests/debuginfo/type-names.rs b/tests/debuginfo/type-names.rs
index d7b79a845d2..c5ce044dd53 100644
--- a/tests/debuginfo/type-names.rs
+++ b/tests/debuginfo/type-names.rs
@@ -175,7 +175,6 @@
 // 0-sized structs appear to be optimized away in some cases, so only check the structs that do
 // actually appear.
 // cdb-command:dv /t *_struct
-// cdb-check:struct type_names::GenericStruct<enum2$<type_names::mod1::Enum2>,f64> mut_generic_struct = [...]
 
 // ENUMS
 // cdb-command:dv /t *_enum_*
diff --git a/tests/incremental/auxiliary/circular-dependencies-aux.rs b/tests/incremental/auxiliary/circular-dependencies-aux.rs
new file mode 100644
index 00000000000..0e74eb1b2f2
--- /dev/null
+++ b/tests/incremental/auxiliary/circular-dependencies-aux.rs
@@ -0,0 +1,10 @@
+// edition: 2021
+// compile-flags: --crate-type lib --extern circular_dependencies={{build-base}}/circular-dependencies/libcircular_dependencies.rmeta --emit dep-info,metadata
+
+use circular_dependencies::Foo;
+
+pub fn consume_foo(_: Foo) {}
+
+pub fn produce_foo() -> Foo {
+    Foo
+}
diff --git a/tests/incremental/circular-dependencies.rs b/tests/incremental/circular-dependencies.rs
new file mode 100644
index 00000000000..10673066a9d
--- /dev/null
+++ b/tests/incremental/circular-dependencies.rs
@@ -0,0 +1,37 @@
+// ignore-tidy-linelength
+// revisions: cpass1 cfail2
+// edition: 2021
+// [cpass1] compile-flags: --crate-type lib --emit dep-info,metadata
+// [cfail2] aux-build: circular-dependencies-aux.rs
+// [cfail2] compile-flags: --test --extern aux={{build-base}}/circular-dependencies/auxiliary/libcircular_dependencies_aux.rmeta -L dependency={{build-base}}/circular-dependencies
+
+pub struct Foo;
+//[cfail2]~^ NOTE `Foo` is defined in the current crate
+//[cfail2]~| NOTE `Foo` is defined in the current crate
+//[cfail2]~| NOTE `circular_dependencies::Foo` is defined in crate `circular_dependencies`
+//[cfail2]~| NOTE `circular_dependencies::Foo` is defined in crate `circular_dependencies`
+
+pub fn consume_foo(_: Foo) {}
+//[cfail2]~^ NOTE function defined here
+
+pub fn produce_foo() -> Foo {
+    Foo
+}
+
+#[test]
+fn test() {
+    aux::consume_foo(produce_foo());
+    //[cfail2]~^ ERROR mismatched types [E0308]
+    //[cfail2]~| NOTE expected `circular_dependencies::Foo`, found `Foo`
+    //[cfail2]~| NOTE arguments to this function are incorrect
+    //[cfail2]~| NOTE `Foo` and `circular_dependencies::Foo` have similar names, but are actually distinct types
+    //[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations
+    //[cfail2]~| NOTE function defined here
+
+    consume_foo(aux::produce_foo());
+    //[cfail2]~^ ERROR mismatched types [E0308]
+    //[cfail2]~| NOTE expected `Foo`, found `circular_dependencies::Foo`
+    //[cfail2]~| NOTE arguments to this function are incorrect
+    //[cfail2]~| NOTE `circular_dependencies::Foo` and `Foo` have similar names, but are actually distinct types
+    //[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations
+}
diff --git a/tests/incremental/hashes/let_expressions.rs b/tests/incremental/hashes/let_expressions.rs
index 180bf6fec87..7aca4324233 100644
--- a/tests/incremental/hashes/let_expressions.rs
+++ b/tests/incremental/hashes/let_expressions.rs
@@ -193,9 +193,9 @@ pub fn add_initializer() {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_initializer() {
     let _x: i16 = 3i16;
diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
index ad4e5c6fcfd..9ad8a70a2ce 100644
--- a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
+++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
@@ -4,7 +4,7 @@
         _0: GeneratorSavedTy {
             ty: impl std::future::Future<Output = ()>,
             source_info: SourceInfo {
-                span: $DIR/async_await.rs:15:8: 15:14 (#9),
+                span: $DIR/async_await.rs:15:8: 15:14 (#8),
                 scope: scope[0],
             },
             ignore_for_traits: false,
@@ -12,7 +12,7 @@
         _1: GeneratorSavedTy {
             ty: impl std::future::Future<Output = ()>,
             source_info: SourceInfo {
-                span: $DIR/async_await.rs:16:8: 16:14 (#12),
+                span: $DIR/async_await.rs:16:8: 16:14 (#11),
                 scope: scope[0],
             },
             ignore_for_traits: false,
diff --git a/tests/mir-opt/building/custom/aggregate_exprs.adt.built.after.mir b/tests/mir-opt/building/custom/aggregate_exprs.adt.built.after.mir
new file mode 100644
index 00000000000..49e8c812c19
--- /dev/null
+++ b/tests/mir-opt/building/custom/aggregate_exprs.adt.built.after.mir
@@ -0,0 +1,16 @@
+// MIR for `adt` after built
+
+fn adt() -> Onion {
+    let mut _0: Onion;                   // return place in scope 0 at $DIR/aggregate_exprs.rs:+0:13: +0:18
+    let mut _1: i32;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _2: Foo;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _3: Bar;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _1 = const 1_i32;                // scope 0 at $DIR/aggregate_exprs.rs:+6:13: +6:20
+        _2 = Foo { a: const 1_i32, b: const 2_i32 }; // scope 0 at $DIR/aggregate_exprs.rs:+7:13: +10:14
+        _3 = Bar::Foo(move _2, _1);      // scope 0 at $DIR/aggregate_exprs.rs:+11:13: +11:39
+        _0 = Onion { neon: ((_3 as variant#0).1: i32) }; // scope 0 at $DIR/aggregate_exprs.rs:+12:13: +12:58
+        return;                          // scope 0 at $DIR/aggregate_exprs.rs:+13:13: +13:21
+    }
+}
diff --git a/tests/mir-opt/building/custom/aggregate_exprs.array.built.after.mir b/tests/mir-opt/building/custom/aggregate_exprs.array.built.after.mir
new file mode 100644
index 00000000000..30d12897331
--- /dev/null
+++ b/tests/mir-opt/building/custom/aggregate_exprs.array.built.after.mir
@@ -0,0 +1,15 @@
+// MIR for `array` after built
+
+fn array() -> [i32; 2] {
+    let mut _0: [i32; 2];                // return place in scope 0 at $DIR/aggregate_exprs.rs:+0:15: +0:23
+    let mut _1: [i32; 2];                // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _2: i32;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _1 = [const 42_i32, const 43_i32]; // scope 0 at $DIR/aggregate_exprs.rs:+5:13: +5:25
+        _2 = const 1_i32;                // scope 0 at $DIR/aggregate_exprs.rs:+6:13: +6:20
+        _1 = [_2, const 2_i32];          // scope 0 at $DIR/aggregate_exprs.rs:+7:13: +7:25
+        _0 = move _1;                    // scope 0 at $DIR/aggregate_exprs.rs:+8:13: +8:26
+        return;                          // scope 0 at $DIR/aggregate_exprs.rs:+9:13: +9:21
+    }
+}
diff --git a/tests/mir-opt/building/custom/aggregate_exprs.rs b/tests/mir-opt/building/custom/aggregate_exprs.rs
new file mode 100644
index 00000000000..554c9c03ba4
--- /dev/null
+++ b/tests/mir-opt/building/custom/aggregate_exprs.rs
@@ -0,0 +1,71 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+// EMIT_MIR aggregate_exprs.tuple.built.after.mir
+#[custom_mir(dialect = "built")]
+fn tuple() -> (i32, bool) {
+    mir!(
+        {
+            RET = (1, true);
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR aggregate_exprs.array.built.after.mir
+#[custom_mir(dialect = "built")]
+fn array() -> [i32; 2] {
+    mir!(
+        let x: [i32; 2];
+        let one: i32;
+        {
+            x = [42, 43];
+            one = 1;
+            x = [one, 2];
+            RET = Move(x);
+            Return()
+        }
+    )
+}
+
+struct Foo {
+    a: i32,
+    b: i32,
+}
+
+enum Bar {
+    Foo(Foo, i32),
+}
+
+union Onion {
+    neon: i32,
+    noun: f32,
+}
+
+// EMIT_MIR aggregate_exprs.adt.built.after.mir
+#[custom_mir(dialect = "built")]
+fn adt() -> Onion {
+    mir!(
+        let one: i32;
+        let x: Foo;
+        let y: Bar;
+        {
+            one = 1;
+            x = Foo {
+                a: 1,
+                b: 2,
+            };
+            y = Bar::Foo(Move(x), one);
+            RET = Onion { neon: Field(Variant(y, 0), 1) };
+            Return()
+        }
+    )
+}
+
+fn main() {
+    assert_eq!(tuple(), (1, true));
+    assert_eq!(array(), [1, 2]);
+    assert_eq!(unsafe { adt().neon }, 1);
+}
diff --git a/tests/mir-opt/building/custom/aggregate_exprs.tuple.built.after.mir b/tests/mir-opt/building/custom/aggregate_exprs.tuple.built.after.mir
new file mode 100644
index 00000000000..5fe45ccc90c
--- /dev/null
+++ b/tests/mir-opt/building/custom/aggregate_exprs.tuple.built.after.mir
@@ -0,0 +1,10 @@
+// MIR for `tuple` after built
+
+fn tuple() -> (i32, bool) {
+    let mut _0: (i32, bool);             // return place in scope 0 at $DIR/aggregate_exprs.rs:+0:15: +0:26
+
+    bb0: {
+        _0 = (const 1_i32, const true);  // scope 0 at $DIR/aggregate_exprs.rs:+3:13: +3:28
+        return;                          // scope 0 at $DIR/aggregate_exprs.rs:+4:13: +4:21
+    }
+}
diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff
index f270ab8b69f..7e77c18d575 100644
--- a/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff
+++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff
@@ -14,7 +14,6 @@
       }
   
       bb1: {
-          StorageLive(_2);                 // scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
           _2 = begin_panic::<&str>(const "explicit panic"); // scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/std/src/panic.rs:LL:COL
diff --git a/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
index a38c1de2a78..85dedf68ce9 100644
--- a/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
@@ -12,12 +12,10 @@
           let _3: [E; 1];                  // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
           scope 3 {
               debug _invalid_tag => _3;    // in scope 3 at $DIR/invalid_constant.rs:+13:9: +13:21
-              let _6: [Empty; 1];          // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
               scope 5 {
-                  debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
-                  let _7: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
+                  debug _enum_without_variants => const [ZeroSized: Empty]; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
                   scope 7 {
-                      debug _non_utf8_str => _7; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
+                      debug _non_utf8_str => const Str::<"���">; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
                   }
               }
               scope 6 {
@@ -52,10 +50,6 @@
 +                                          // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
           StorageDead(_4);                 // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60
           StorageDead(_5);                 // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61
-          StorageLive(_6);                 // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
-          StorageLive(_7);                 // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
-          StorageDead(_7);                 // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
-          StorageDead(_6);                 // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
           StorageDead(_3);                 // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2
           StorageDead(_1);                 // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2
           return;                          // scope 0 at $DIR/invalid_constant.rs:+27:2: +27:2
diff --git a/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff b/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff
new file mode 100644
index 00000000000..e31c2bc3938
--- /dev/null
+++ b/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff
@@ -0,0 +1,76 @@
+- // MIR for `main` before RemoveZsts
++ // MIR for `main` after RemoveZsts
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/invalid_constant.rs:+0:11: +0:11
+      let _1: char;                        // in scope 0 at $DIR/invalid_constant.rs:+6:9: +6:22
+      let mut _2: main::InvalidChar;       // in scope 0 at $DIR/invalid_constant.rs:+6:34: +6:63
+      let mut _4: E;                       // in scope 0 at $DIR/invalid_constant.rs:+13:25: +13:59
+      let mut _5: main::InvalidTag;        // in scope 0 at $DIR/invalid_constant.rs:+13:34: +13:55
+      let mut _7: Empty;                   // in scope 0 at $DIR/invalid_constant.rs:+20:35: +20:73
+      let mut _8: main::NoVariants;        // in scope 0 at $DIR/invalid_constant.rs:+20:44: +20:65
+      scope 1 {
+          debug _invalid_char => _1;       // in scope 1 at $DIR/invalid_constant.rs:+6:9: +6:22
+          let _3: [E; 1];                  // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
+          scope 3 {
+              debug _invalid_tag => _3;    // in scope 3 at $DIR/invalid_constant.rs:+13:9: +13:21
+              let _6: [Empty; 1];          // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
+              scope 5 {
+-                 debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
++                 debug _enum_without_variants => const [ZeroSized: Empty]; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
+                  let _9: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
+                  scope 7 {
+-                     debug _non_utf8_str => _9; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
++                     debug _non_utf8_str => const Str::<"���">; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
+                  }
+              }
+              scope 6 {
+              }
+          }
+          scope 4 {
+          }
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/invalid_constant.rs:+6:9: +6:22
+          StorageLive(_2);                 // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
+          _2 = InvalidChar { int: const 1114113_u32 }; // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
+          _1 = (_2.1: char);               // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:67
+          StorageDead(_2);                 // scope 0 at $DIR/invalid_constant.rs:+6:69: +6:70
+          StorageLive(_3);                 // scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
+          StorageLive(_4);                 // scope 1 at $DIR/invalid_constant.rs:+13:25: +13:59
+          StorageLive(_5);                 // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
+          _5 = InvalidTag { int: const 4_u32 }; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
+          _4 = (_5.1: E);                  // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57
+          _3 = [move _4];                  // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60
+          StorageDead(_4);                 // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60
+          StorageDead(_5);                 // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61
+-         StorageLive(_6);                 // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
+-         StorageLive(_7);                 // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73
++         nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
++         nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73
+          StorageLive(_8);                 // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
+          _8 = NoVariants { int: const 0_u32 }; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
+-         _7 = (_8.1: Empty);              // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71
+-         _6 = [move _7];                  // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74
+-         StorageDead(_7);                 // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74
++         nop;                             // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71
++         nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74
++         nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74
+          StorageDead(_8);                 // scope 3 at $DIR/invalid_constant.rs:+20:74: +20:75
+-         StorageLive(_9);                 // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
+-         _0 = const ();                   // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2
+-         StorageDead(_9);                 // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
+-         StorageDead(_6);                 // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
++         nop;                             // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
++         nop;                             // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2
++         nop;                             // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
++         nop;                             // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
+          StorageDead(_3);                 // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2
+          StorageDead(_1);                 // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2
+          return;                          // scope 0 at $DIR/invalid_constant.rs:+27:2: +27:2
+      }
+  }
+  
diff --git a/tests/mir-opt/const_prop/invalid_constant.rs b/tests/mir-opt/const_prop/invalid_constant.rs
index 0337a7ca851..eb6172cdff9 100644
--- a/tests/mir-opt/const_prop/invalid_constant.rs
+++ b/tests/mir-opt/const_prop/invalid_constant.rs
@@ -11,6 +11,7 @@ enum E { A, B, C }
 #[derive(Copy, Clone)]
 enum Empty {}
 
+// EMIT_MIR invalid_constant.main.RemoveZsts.diff
 // EMIT_MIR invalid_constant.main.ConstProp.diff
 fn main() {
     // An invalid char.
diff --git a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff b/tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff
index 964dd308074..a4f9003e140 100644
--- a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff
@@ -5,14 +5,10 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/issue_66971.rs:+0:11: +0:11
       let _1: ();                          // in scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
       let mut _2: ((), u8, u8);            // in scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
-      let mut _3: ();                      // in scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
           StorageLive(_2);                 // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
-          StorageLive(_3);                 // scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
-          _2 = (move _3, const 0_u8, const 0_u8); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
-          StorageDead(_3);                 // scope 0 at $DIR/issue_66971.rs:+1:21: +1:22
+          _2 = (const (), const 0_u8, const 0_u8); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
           _1 = encode(move _2) -> bb1;     // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
                                            // mir::Constant
                                            // + span: $DIR/issue_66971.rs:17:5: 17:11
@@ -21,7 +17,6 @@
   
       bb1: {
           StorageDead(_2);                 // scope 0 at $DIR/issue_66971.rs:+1:22: +1:23
-          StorageDead(_1);                 // scope 0 at $DIR/issue_66971.rs:+1:23: +1:24
           return;                          // scope 0 at $DIR/issue_66971.rs:+2:2: +2:2
       }
   }
diff --git a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff
index a631cb31090..f456a321204 100644
--- a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff
@@ -8,7 +8,6 @@
       let mut _3: (u8, u8);                // in scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/issue_67019.rs:+1:5: +1:20
           StorageLive(_2);                 // scope 0 at $DIR/issue_67019.rs:+1:10: +1:19
           StorageLive(_3);                 // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
 -         _3 = (const 1_u8, const 2_u8);   // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
@@ -23,7 +22,6 @@
   
       bb1: {
           StorageDead(_2);                 // scope 0 at $DIR/issue_67019.rs:+1:19: +1:20
-          StorageDead(_1);                 // scope 0 at $DIR/issue_67019.rs:+1:20: +1:21
           return;                          // scope 0 at $DIR/issue_67019.rs:+2:2: +2:2
       }
   }
diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
index 22f710387db..1151caaabbc 100644
--- a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
@@ -12,7 +12,6 @@
   
       bb0: {
           _1 = const 1_u32;                // scope 0 at $DIR/scalar_literal_propagation.rs:+1:13: +1:14
-          StorageLive(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
 -         _2 = consume(_1) -> bb1;         // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
 +         _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
                                            // mir::Constant
@@ -21,7 +20,6 @@
       }
   
       bb1: {
-          StorageDead(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16
           return;                          // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2
       }
   }
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
index 270a1ccf560..d370abce45a 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
@@ -13,7 +13,6 @@
       bb0: {
 -         _1 = (const 1_u32, const 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
 +         _1 = const (1_u32, 2_u32);       // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
-          StorageLive(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
           _2 = consume(_1) -> bb1;         // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
                                            // mir::Constant
                                            // + span: $DIR/tuple_literal_propagation.rs:5:5: 5:12
@@ -21,7 +20,6 @@
       }
   
       bb1: {
-          StorageDead(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:15: +3:16
           return;                          // scope 0 at $DIR/tuple_literal_propagation.rs:+4:2: +4:2
       }
   }
diff --git a/tests/mir-opt/inline/asm_unwind.main.Inline.diff b/tests/mir-opt/inline/asm_unwind.main.Inline.diff
index f1b62ac38ba..ed290063a93 100644
--- a/tests/mir-opt/inline/asm_unwind.main.Inline.diff
+++ b/tests/mir-opt/inline/asm_unwind.main.Inline.diff
@@ -7,7 +7,7 @@
 +     scope 1 (inlined foo) {              // at $DIR/asm_unwind.rs:21:5: 21:10
 +         let _2: D;                       // in scope 1 at $DIR/asm_unwind.rs:15:9: 15:11
 +         scope 2 {
-+             debug _d => _2;              // in scope 2 at $DIR/asm_unwind.rs:15:9: 15:11
++             debug _d => const D;         // in scope 2 at $DIR/asm_unwind.rs:15:9: 15:11
 +             scope 3 {
 +             }
 +         }
@@ -19,21 +19,21 @@
 -                                          // mir::Constant
 -                                          // + span: $DIR/asm_unwind.rs:21:5: 21:8
 -                                          // + literal: Const { ty: fn() {foo}, val: Value(<ZST>) }
-+         StorageLive(_2);                 // scope 1 at $DIR/asm_unwind.rs:15:9: 15:11
-+         asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind: bb3]; // scope 3 at $DIR/asm_unwind.rs:16:14: 16:54
++         StorageLive(_2);                 // scope 0 at $DIR/asm_unwind.rs:+1:5: +1:10
++         asm!("", options(MAY_UNWIND)) -> [return: bb2, unwind: bb3]; // scope 3 at $DIR/asm_unwind.rs:16:14: 16:54
       }
   
       bb1: {
-+         drop(_2) -> bb2;                 // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2
-+     }
-+ 
-+     bb2: {
-+         StorageDead(_2);                 // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2
++         StorageDead(_2);                 // scope 0 at $DIR/asm_unwind.rs:+1:5: +1:10
           StorageDead(_1);                 // scope 0 at $DIR/asm_unwind.rs:+1:10: +1:11
           _0 = const ();                   // scope 0 at $DIR/asm_unwind.rs:+0:15: +2:2
           return;                          // scope 0 at $DIR/asm_unwind.rs:+2:2: +2:2
 +     }
 + 
++     bb2: {
++         drop(_2) -> bb1;                 // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2
++     }
++ 
 +     bb3 (cleanup): {
 +         drop(_2) -> bb4;                 // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2
 +     }
diff --git a/tests/mir-opt/inline/cycle.g.Inline.diff b/tests/mir-opt/inline/cycle.g.Inline.diff
index 5f3ee467c88..20d313aecf5 100644
--- a/tests/mir-opt/inline/cycle.g.Inline.diff
+++ b/tests/mir-opt/inline/cycle.g.Inline.diff
@@ -5,11 +5,11 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/cycle.rs:+0:8: +0:8
       let _1: ();                          // in scope 0 at $DIR/cycle.rs:+1:5: +1:12
 +     let mut _2: fn() {main};             // in scope 0 at $DIR/cycle.rs:+1:5: +1:12
++     let mut _5: ();                      // in scope 0 at $DIR/cycle.rs:6:5: 6:8
 +     scope 1 (inlined f::<fn() {main}>) { // at $DIR/cycle.rs:12:5: 12:12
 +         debug g => _2;                   // in scope 1 at $DIR/cycle.rs:5:6: 5:7
 +         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         let mut _4: &fn() {main};        // in scope 1 at $DIR/cycle.rs:6:5: 6:6
-+         let mut _5: ();                  // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
 +         }
 +     }
@@ -25,14 +25,16 @@
 -                                          // mir::Constant
                                            // + span: $DIR/cycle.rs:12:7: 12:11
                                            // + literal: Const { ty: fn() {main}, val: Value(<ZST>) }
-+         StorageLive(_3);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         StorageLive(_3);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:12
 +         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         _5 = const ();                   // scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
++         StorageDead(_3);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:12
 +         StorageDead(_2);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:12
           StorageDead(_1);                 // scope 0 at $DIR/cycle.rs:+1:12: +1:13
           _0 = const ();                   // scope 0 at $DIR/cycle.rs:+0:8: +2:2
@@ -48,9 +50,8 @@
 +     }
 + 
 +     bb4: {
-+         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
 +         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
       }
   }
diff --git a/tests/mir-opt/inline/cycle.main.Inline.diff b/tests/mir-opt/inline/cycle.main.Inline.diff
index 6b4c63bbd91..dacc5f4be9d 100644
--- a/tests/mir-opt/inline/cycle.main.Inline.diff
+++ b/tests/mir-opt/inline/cycle.main.Inline.diff
@@ -5,11 +5,11 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/cycle.rs:+0:11: +0:11
       let _1: ();                          // in scope 0 at $DIR/cycle.rs:+1:5: +1:9
 +     let mut _2: fn() {g};                // in scope 0 at $DIR/cycle.rs:+1:5: +1:9
++     let mut _5: ();                      // in scope 0 at $DIR/cycle.rs:6:5: 6:8
 +     scope 1 (inlined f::<fn() {g}>) {    // at $DIR/cycle.rs:17:5: 17:9
 +         debug g => _2;                   // in scope 1 at $DIR/cycle.rs:5:6: 5:7
 +         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         let mut _4: &fn() {g};           // in scope 1 at $DIR/cycle.rs:6:5: 6:6
-+         let mut _5: ();                  // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8
 +         }
 +     }
@@ -25,14 +25,16 @@
 -                                          // mir::Constant
                                            // + span: $DIR/cycle.rs:17:7: 17:8
                                            // + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
-+         StorageLive(_3);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         StorageLive(_3);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:9
 +         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         _5 = const ();                   // scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
++         StorageDead(_3);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:9
 +         StorageDead(_2);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:9
           StorageDead(_1);                 // scope 0 at $DIR/cycle.rs:+1:9: +1:10
           _0 = const ();                   // scope 0 at $DIR/cycle.rs:+0:11: +2:2
@@ -48,9 +50,8 @@
 +     }
 + 
 +     bb4: {
-+         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
 +         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
       }
   }
diff --git a/tests/mir-opt/inline/exponential_runtime.main.Inline.diff b/tests/mir-opt/inline/exponential_runtime.main.Inline.diff
index 7fd62be7ab9..dd1f253cb47 100644
--- a/tests/mir-opt/inline/exponential_runtime.main.Inline.diff
+++ b/tests/mir-opt/inline/exponential_runtime.main.Inline.diff
@@ -18,9 +18,13 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
 -         _1 = <() as G>::call() -> bb1;   // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
-+         StorageLive(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+         StorageLive(_5);                 // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
-+         _5 = <() as E>::call() -> bb3;   // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
++         StorageLive(_2);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
++         StorageLive(_3);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
++         StorageLive(_4);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
++         StorageLive(_5);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++         StorageLive(_6);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++         StorageLive(_7);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++         _5 = <() as E>::call() -> bb4;   // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
                                            // mir::Constant
 -                                          // + span: $DIR/exponential_runtime.rs:86:5: 86:20
 -                                          // + literal: Const { ty: fn() {<() as G>::call}, val: Value(<ZST>) }
@@ -29,47 +33,43 @@
       }
   
       bb1: {
-+         StorageDead(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:25: 74:26
-+         StorageLive(_4);                 // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
-+         _4 = <() as F>::call() -> bb2;   // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
-+                                          // mir::Constant
-+                                          // + span: $DIR/exponential_runtime.rs:75:9: 75:23
-+                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
-+     }
-+ 
-+     bb2: {
-+         StorageDead(_4);                 // scope 1 at $DIR/exponential_runtime.rs:75:25: 75:26
++         StorageDead(_4);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
++         StorageDead(_3);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
++         StorageDead(_2);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
           StorageDead(_1);                 // scope 0 at $DIR/exponential_runtime.rs:+1:22: +1:23
           _0 = const ();                   // scope 0 at $DIR/exponential_runtime.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/exponential_runtime.rs:+2:2: +2:2
 +     }
 + 
++     bb2: {
++         StorageDead(_7);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++         StorageDead(_6);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++         StorageDead(_5);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++         _3 = <() as F>::call() -> bb3;   // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:74:9: 74:23
++                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
++     }
++ 
 +     bb3: {
-+         StorageDead(_5);                 // scope 2 at $DIR/exponential_runtime.rs:61:25: 61:26
-+         StorageLive(_6);                 // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
-+         _6 = <() as E>::call() -> bb4;   // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++         _4 = <() as F>::call() -> bb1;   // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
 +                                          // mir::Constant
-+                                          // + span: $DIR/exponential_runtime.rs:62:9: 62:23
-+                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
++                                          // + span: $DIR/exponential_runtime.rs:75:9: 75:23
++                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
 +     }
 + 
 +     bb4: {
-+         StorageDead(_6);                 // scope 2 at $DIR/exponential_runtime.rs:62:25: 62:26
-+         StorageLive(_7);                 // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
-+         _7 = <() as E>::call() -> bb5;   // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++         _6 = <() as E>::call() -> bb5;   // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
 +                                          // mir::Constant
-+                                          // + span: $DIR/exponential_runtime.rs:63:9: 63:23
++                                          // + span: $DIR/exponential_runtime.rs:62:9: 62:23
 +                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
 +     }
 + 
 +     bb5: {
-+         StorageDead(_7);                 // scope 2 at $DIR/exponential_runtime.rs:63:25: 63:26
-+         StorageDead(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
-+         StorageLive(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+         _3 = <() as F>::call() -> bb1;   // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         _7 = <() as E>::call() -> bb2;   // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
 +                                          // mir::Constant
-+                                          // + span: $DIR/exponential_runtime.rs:74:9: 74:23
-+                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
++                                          // + span: $DIR/exponential_runtime.rs:63:9: 63:23
++                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
       }
   }
   
diff --git a/tests/mir-opt/inline/inline_cycle.two.Inline.diff b/tests/mir-opt/inline/inline_cycle.two.Inline.diff
index 64c0065b543..0215b3d93f9 100644
--- a/tests/mir-opt/inline/inline_cycle.two.Inline.diff
+++ b/tests/mir-opt/inline/inline_cycle.two.Inline.diff
@@ -5,10 +5,10 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
       let _1: ();                          // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
 +     let mut _2: fn() {f};                // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
++     let mut _4: ();                      // in scope 0 at $DIR/inline_cycle.rs:54:5: 54:8
 +     scope 1 (inlined call::<fn() {f}>) { // at $DIR/inline_cycle.rs:49:5: 49:12
 +         debug f => _2;                   // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23
 +         let _3: ();                      // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+         let mut _4: ();                  // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
 +         scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8
 +         }
 +     }
@@ -24,14 +24,15 @@
 -                                          // mir::Constant
                                            // + span: $DIR/inline_cycle.rs:49:10: 49:11
                                            // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
-+         StorageLive(_3);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++         StorageLive(_3);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
 +         StorageLive(_4);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++         _4 = const ();                   // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
 +         _3 = move _2() -> bb1;           // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
-+         StorageDead(_4);                 // scope 1 at $DIR/inline_cycle.rs:54:7: 54:8
-+         StorageDead(_3);                 // scope 1 at $DIR/inline_cycle.rs:54:8: 54:9
++         StorageDead(_4);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++         StorageDead(_3);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
 +         StorageDead(_2);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
           StorageDead(_1);                 // scope 0 at $DIR/inline_cycle.rs:+1:12: +1:13
           _0 = const ();                   // scope 0 at $DIR/inline_cycle.rs:+0:10: +2:2
diff --git a/tests/mir-opt/inline/inline_diverging.g.Inline.diff b/tests/mir-opt/inline/inline_diverging.g.Inline.diff
index b787a19f4b2..4f22ad43700 100644
--- a/tests/mir-opt/inline/inline_diverging.g.Inline.diff
+++ b/tests/mir-opt/inline/inline_diverging.g.Inline.diff
@@ -34,7 +34,7 @@
       bb2: {
           StorageLive(_6);                 // scope 0 at $DIR/inline_diverging.rs:+4:9: +4:16
 -         _6 = panic();                    // scope 0 at $DIR/inline_diverging.rs:+4:9: +4:16
-+         StorageLive(_7);                 // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
++         StorageLive(_7);                 // scope 0 at $DIR/inline_diverging.rs:+4:9: +4:16
 +         _7 = begin_panic::<&str>(const "explicit panic"); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
                                            // mir::Constant
 -                                          // + span: $DIR/inline_diverging.rs:16:9: 16:14
diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.diff
index e1b2f7dbf35..31208e0052c 100644
--- a/tests/mir-opt/inline/inline_diverging.h.Inline.diff
+++ b/tests/mir-opt/inline/inline_diverging.h.Inline.diff
@@ -5,19 +5,18 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/inline_diverging.rs:+0:12: +0:12
       let _1: (!, !);                      // in scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22
 +     let mut _2: fn() -> ! {sleep};       // in scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22
++     let mut _8: ();                      // in scope 0 at $DIR/inline_diverging.rs:27:13: 27:16
 +     scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline_diverging.rs:22:5: 22:22
 +         debug f => _2;                   // in scope 1 at $DIR/inline_diverging.rs:26:36: 26:37
 +         let _3: !;                       // in scope 1 at $DIR/inline_diverging.rs:27:9: 27:10
 +         let mut _4: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
-+         let mut _5: ();                  // in scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+         let mut _6: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline_diverging.rs:28:13: 28:14
-+         let mut _7: ();                  // in scope 1 at $DIR/inline_diverging.rs:28:13: 28:16
-+         let mut _8: !;                   // in scope 1 at $DIR/inline_diverging.rs:29:6: 29:7
-+         let mut _9: !;                   // in scope 1 at $DIR/inline_diverging.rs:29:9: 29:10
++         let mut _5: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline_diverging.rs:28:13: 28:14
++         let mut _6: !;                   // in scope 1 at $DIR/inline_diverging.rs:29:6: 29:7
++         let mut _7: !;                   // in scope 1 at $DIR/inline_diverging.rs:29:9: 29:10
 +         scope 2 {
 +             debug a => _3;               // in scope 2 at $DIR/inline_diverging.rs:27:9: 27:10
 +             scope 3 {
-+                 debug b => _9;           // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
++                 debug b => _7;           // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
 +             }
 +         }
 +         scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16
@@ -35,21 +34,21 @@
 -                                          // mir::Constant
                                            // + span: $DIR/inline_diverging.rs:22:16: 22:21
                                            // + literal: Const { ty: fn() -> ! {sleep}, val: Value(<ZST>) }
-+         StorageLive(_9);                 // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22
++         StorageLive(_7);                 // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22
 +         StorageLive(_3);                 // scope 1 at $DIR/inline_diverging.rs:27:9: 27:10
 +         StorageLive(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
 +         _4 = &_2;                        // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
-+         StorageLive(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
++         StorageLive(_8);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
++         _8 = const ();                   // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
 +         _3 = move (*_4)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL
 +     }
 + 
 +     bb1: {
-+         StorageDead(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
-+         StorageDead(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
-+         StorageLive(_8);                 // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
-+         _8 = move _3;                    // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
-+         _1 = (move _8, move _9);         // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
-+         StorageDead(_8);                 // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
++         StorageDead(_5);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
++         StorageLive(_6);                 // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
++         _6 = move _3;                    // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
++         _1 = (move _6, move _7);         // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
++         StorageDead(_6);                 // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
 +         StorageDead(_3);                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +         drop(_2) -> bb2;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +     }
@@ -71,12 +70,11 @@
 +     }
 + 
 +     bb6: {
-+         StorageDead(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++         StorageDead(_8);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
 +         StorageDead(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
-+         StorageLive(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+         _6 = &_2;                        // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+         StorageLive(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
-+         _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++         StorageLive(_5);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++         _5 = &_2;                        // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++         _7 = <fn() -> ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
 +                                          // mir::Constant
 +                                          // + span: $DIR/inline_diverging.rs:28:13: 28:14
 +                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
diff --git a/tests/mir-opt/inline/inline_options.main.Inline.after.mir b/tests/mir-opt/inline/inline_options.main.Inline.after.mir
index 1c590be945c..abe26bd8ce3 100644
--- a/tests/mir-opt/inline/inline_options.main.Inline.after.mir
+++ b/tests/mir-opt/inline/inline_options.main.Inline.after.mir
@@ -21,35 +21,35 @@ fn main() -> () {
     bb1: {
         StorageDead(_1);                 // scope 0 at $DIR/inline_options.rs:+1:18: +1:19
         StorageLive(_2);                 // scope 0 at $DIR/inline_options.rs:+2:5: +2:21
-        StorageLive(_3);                 // scope 1 at $DIR/inline_options.rs:16:23: 16:26
-        _3 = g() -> bb2;                 // scope 1 at $DIR/inline_options.rs:16:23: 16:26
+        StorageLive(_3);                 // scope 0 at $DIR/inline_options.rs:+2:5: +2:21
+        StorageLive(_4);                 // scope 0 at $DIR/inline_options.rs:+2:5: +2:21
+        StorageLive(_5);                 // scope 0 at $DIR/inline_options.rs:+2:5: +2:21
+        _3 = g() -> bb3;                 // scope 1 at $DIR/inline_options.rs:16:23: 16:26
                                          // mir::Constant
                                          // + span: $DIR/inline_options.rs:16:23: 16:24
                                          // + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
     }
 
     bb2: {
-        StorageDead(_3);                 // scope 1 at $DIR/inline_options.rs:16:26: 16:27
-        StorageLive(_4);                 // scope 1 at $DIR/inline_options.rs:16:28: 16:31
-        _4 = g() -> bb3;                 // scope 1 at $DIR/inline_options.rs:16:28: 16:31
-                                         // mir::Constant
-                                         // + span: $DIR/inline_options.rs:16:28: 16:29
-                                         // + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
+        StorageDead(_5);                 // scope 0 at $DIR/inline_options.rs:+2:5: +2:21
+        StorageDead(_4);                 // scope 0 at $DIR/inline_options.rs:+2:5: +2:21
+        StorageDead(_3);                 // scope 0 at $DIR/inline_options.rs:+2:5: +2:21
+        StorageDead(_2);                 // scope 0 at $DIR/inline_options.rs:+2:21: +2:22
+        _0 = const ();                   // scope 0 at $DIR/inline_options.rs:+0:11: +3:2
+        return;                          // scope 0 at $DIR/inline_options.rs:+3:2: +3:2
     }
 
     bb3: {
-        StorageDead(_4);                 // scope 1 at $DIR/inline_options.rs:16:31: 16:32
-        StorageLive(_5);                 // scope 1 at $DIR/inline_options.rs:16:33: 16:36
-        _5 = g() -> bb4;                 // scope 1 at $DIR/inline_options.rs:16:33: 16:36
+        _4 = g() -> bb4;                 // scope 1 at $DIR/inline_options.rs:16:28: 16:31
                                          // mir::Constant
-                                         // + span: $DIR/inline_options.rs:16:33: 16:34
+                                         // + span: $DIR/inline_options.rs:16:28: 16:29
                                          // + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
     }
 
     bb4: {
-        StorageDead(_5);                 // scope 1 at $DIR/inline_options.rs:16:36: 16:37
-        StorageDead(_2);                 // scope 0 at $DIR/inline_options.rs:+2:21: +2:22
-        _0 = const ();                   // scope 0 at $DIR/inline_options.rs:+0:11: +3:2
-        return;                          // scope 0 at $DIR/inline_options.rs:+3:2: +3:2
+        _5 = g() -> bb2;                 // scope 1 at $DIR/inline_options.rs:16:33: 16:36
+                                         // mir::Constant
+                                         // + span: $DIR/inline_options.rs:16:33: 16:34
+                                         // + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
     }
 }
diff --git a/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir b/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
index 4dd1aad489d..a98c294cacb 100644
--- a/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
+++ b/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
@@ -10,10 +10,9 @@ fn main() -> () {
     scope 1 {
         debug f => _1;                   // in scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:9: +1:10
         scope 2 (inlined main::{closure#0}) { // at $DIR/issue_76997_inline_scopes_parenting.rs:6:5: 6:10
-            debug x => _5;               // in scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:14: +1:15
-            let _6: ();                  // in scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:23: +1:24
+            debug x => const ();         // in scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:14: +1:15
             scope 3 {
-                debug y => _6;           // in scope 3 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:23: +1:24
+                debug y => const ();     // in scope 3 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:23: +1:24
             }
         }
     }
@@ -36,8 +35,6 @@ fn main() -> () {
         _3 = (move _4,);                 // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
         StorageLive(_5);                 // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
         _5 = move (_3.0: ());            // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
-        StorageLive(_6);                 // scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:23: +1:24
-        StorageDead(_6);                 // scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:32: +1:33
         StorageDead(_5);                 // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
         StorageDead(_4);                 // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:9: +2:10
         StorageDead(_3);                 // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:9: +2:10
diff --git a/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff
index 8ff64c1ea15..7031c3f3e69 100644
--- a/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff
+++ b/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff
@@ -8,7 +8,7 @@
       let _3: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46
           _1 = assert_inhabited::<T>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46
                                            // mir::Constant
                                            // + span: $DIR/intrinsic_asserts.rs:25:5: 25:44
@@ -16,8 +16,8 @@
       }
   
       bb1: {
-          StorageDead(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:46: +1:47
-          StorageLive(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+1:46: +1:47
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47
           _2 = assert_zero_valid::<T>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47
                                            // mir::Constant
                                            // + span: $DIR/intrinsic_asserts.rs:26:5: 26:45
@@ -25,8 +25,8 @@
       }
   
       bb2: {
-          StorageDead(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:47: +2:48
-          StorageLive(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+2:47: +2:48
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
           _3 = assert_mem_uninitialized_valid::<T>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
                                            // mir::Constant
                                            // + span: $DIR/intrinsic_asserts.rs:27:5: 27:58
@@ -34,7 +34,7 @@
       }
   
       bb3: {
-          StorageDead(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:60: +3:61
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+3:60: +3:61
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+0:21: +4:2
           return;                          // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2
       }
diff --git a/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff
index ddc01590315..4caa9971fef 100644
--- a/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff
+++ b/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff
@@ -8,7 +8,7 @@
       let _3: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
 -         _1 = assert_inhabited::<Never>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
 +         _1 = assert_inhabited::<Never>(); // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
                                            // mir::Constant
@@ -17,8 +17,8 @@
       }
   
       bb1: {
-          StorageDead(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:50: +1:51
-          StorageLive(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+1:50: +1:51
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
 -         _2 = assert_zero_valid::<&u8>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
 +         _2 = assert_zero_valid::<&u8>(); // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
                                            // mir::Constant
@@ -28,8 +28,8 @@
       }
   
       bb2: {
-          StorageDead(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:49: +2:50
-          StorageLive(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+2:49: +2:50
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
 -         _3 = assert_mem_uninitialized_valid::<&u8>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
 +         _3 = assert_mem_uninitialized_valid::<&u8>(); // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
                                            // mir::Constant
@@ -39,7 +39,7 @@
       }
   
       bb3: {
-          StorageDead(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:62: +3:63
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+3:62: +3:63
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+0:17: +4:2
           return;                          // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2
       }
diff --git a/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff
index 568fbf1a0d6..b0bec957369 100644
--- a/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff
+++ b/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff
@@ -8,7 +8,7 @@
       let _3: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
 -         _1 = assert_inhabited::<()>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
 -                                          // mir::Constant
 -                                          // + span: $DIR/intrinsic_asserts.rs:7:5: 7:45
@@ -17,8 +17,8 @@
       }
   
       bb1: {
-          StorageDead(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:47: +1:48
-          StorageLive(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+1:47: +1:48
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
 -         _2 = assert_zero_valid::<u8>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
 -                                          // mir::Constant
 -                                          // + span: $DIR/intrinsic_asserts.rs:8:5: 8:46
@@ -27,8 +27,8 @@
       }
   
       bb2: {
-          StorageDead(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:48: +2:49
-          StorageLive(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+2:48: +2:49
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
 -         _3 = assert_mem_uninitialized_valid::<u8>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
 -                                          // mir::Constant
 -                                          // + span: $DIR/intrinsic_asserts.rs:9:5: 9:59
@@ -37,7 +37,7 @@
       }
   
       bb3: {
-          StorageDead(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:61: +3:62
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+3:61: +3:62
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+0:20: +4:2
           return;                          // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2
       }
diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.diff b/tests/mir-opt/issue_101973.inner.ConstProp.diff
index 6db8e4d2664..fb0b3866e69 100644
--- a/tests/mir-opt/issue_101973.inner.ConstProp.diff
+++ b/tests/mir-opt/issue_101973.inner.ConstProp.diff
@@ -12,13 +12,14 @@
       let mut _7: u32;                     // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
       let mut _8: u32;                     // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       let mut _9: u32;                     // in scope 0 at $DIR/issue_101973.rs:+1:33: +1:39
-      let mut _10: (u32, bool);            // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-      let mut _11: (u32, bool);            // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+      let mut _10: i32;                    // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+      let mut _11: bool;                   // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+      let mut _12: i32;                    // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+      let mut _13: bool;                   // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       scope 1 (inlined imm8) {             // at $DIR/issue_101973.rs:14:5: 14:17
           debug x => _1;                   // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14
-          let mut _12: u32;                // in scope 1 at $DIR/issue_101973.rs:7:12: 7:27
-          let mut _13: u32;                // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20
-          let mut _14: (u32, bool);        // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20
+          let mut _14: u32;                // in scope 1 at $DIR/issue_101973.rs:7:12: 7:27
+          let mut _15: u32;                // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20
           scope 2 {
               debug out => _4;             // in scope 2 at $DIR/issue_101973.rs:6:9: 6:16
           }
@@ -32,43 +33,46 @@
           StorageLive(_2);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
           StorageLive(_3);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:58
           StorageLive(_4);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:17
-          StorageLive(_12);                // scope 2 at $DIR/issue_101973.rs:7:12: 7:27
-          StorageLive(_13);                // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
-          _14 = CheckedShr(_1, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
-          assert(!move (_14.1: bool), "attempt to shift right by `{}`, which would overflow", const 0_i32) -> bb3; // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
+          StorageLive(_14);                // scope 2 at $DIR/issue_101973.rs:7:12: 7:27
+          StorageLive(_15);                // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
+          _15 = Shr(_1, const 0_i32);      // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
+          _14 = BitAnd(move _15, const 255_u32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:27
+          StorageDead(_15);                // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
+          _4 = BitOr(const 0_u32, move _14); // scope 2 at $DIR/issue_101973.rs:7:5: 7:27
+          StorageDead(_14);                // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
+          StorageLive(_6);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+          StorageLive(_7);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
+          StorageLive(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+-         _10 = BitAnd(const 8_i32, const -32_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+-         _11 = Ne(move _10, const 0_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+-         assert(!move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
++         _10 = const 0_i32;               // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
++         _11 = const false;               // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
++         assert(!const false, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       }
   
       bb1: {
-          _8 = move (_10.0: u32);          // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+          _8 = Shr(_1, const 8_i32);       // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
           _7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
           StorageDead(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:51: +1:52
-          _11 = CheckedShl(_7, const 1_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
-          assert(!move (_11.1: bool), "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+-         _12 = BitAnd(const 1_i32, const -32_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+-         _13 = Ne(move _12, const 0_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+-         assert(!move _13, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
++         _12 = const 0_i32;               // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
++         _13 = const false;               // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
++         assert(!const false, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       }
   
       bb2: {
-          _6 = move (_11.0: u32);          // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+          _6 = Shl(move _7, const 1_i32);  // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
           StorageDead(_7);                 // scope 0 at $DIR/issue_101973.rs:+1:56: +1:57
-          _3 = rotate_right::<u32>(_4, _6) -> bb4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+          _3 = rotate_right::<u32>(_4, _6) -> bb3; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
                                            // + literal: Const { ty: extern "rust-intrinsic" fn(u32, u32) -> u32 {rotate_right::<u32>}, val: Value(<ZST>) }
       }
   
       bb3: {
-          _13 = move (_14.0: u32);         // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
-          _12 = BitAnd(move _13, const 255_u32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:27
-          StorageDead(_13);                // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
-          _4 = BitOr(const 0_u32, move _12); // scope 2 at $DIR/issue_101973.rs:7:5: 7:27
-          StorageDead(_12);                // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
-          StorageLive(_6);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
-          StorageLive(_7);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
-          StorageLive(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-          _10 = CheckedShr(_1, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-          assert(!move (_10.1: bool), "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-      }
-  
-      bb4: {
           StorageDead(_6);                 // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58
           StorageDead(_4);                 // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58
           _2 = move _3 as i32 (IntToInt);  // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff
index cc4f7cc0699..abb89b91dd3 100644
--- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff
+++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff
@@ -42,7 +42,6 @@
       }
   
       bb1: {
-          StorageLive(_15);                // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
           _15 = core::panicking::panic(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/panic.rs:LL:COL
diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
index 291fc5063d2..6e28fb61b6b 100644
--- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
+++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
@@ -66,7 +66,6 @@ fn num_to_digit(_1: char) -> u32 {
     }
 
     bb6: {
-        StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
         _8 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value"); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/option.rs:LL:COL
diff --git a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff
new file mode 100644
index 00000000000..e535141e772
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff
@@ -0,0 +1,54 @@
+- // MIR for `option_payload` before LowerIntrinsics
++ // MIR for `option_payload` after LowerIntrinsics
+  
+  fn option_payload(_1: &Option<usize>, _2: &Option<String>) -> () {
+      debug o => _1;                       // in scope 0 at $DIR/lower_intrinsics.rs:+0:23: +0:24
+      debug p => _2;                       // in scope 0 at $DIR/lower_intrinsics.rs:+0:42: +0:43
+      let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:62: +0:62
+      let mut _4: *const std::option::Option<usize>; // in scope 0 at $DIR/lower_intrinsics.rs:+2:55: +2:56
+      let mut _6: *const std::option::Option<std::string::String>; // in scope 0 at $DIR/lower_intrinsics.rs:+3:55: +3:56
+      scope 1 {
+          let _3: *const usize;            // in scope 1 at $DIR/lower_intrinsics.rs:+2:13: +2:15
+          scope 2 {
+              debug _x => _3;              // in scope 2 at $DIR/lower_intrinsics.rs:+2:13: +2:15
+              let _5: *const std::string::String; // in scope 2 at $DIR/lower_intrinsics.rs:+3:13: +3:15
+              scope 3 {
+                  debug _y => _5;          // in scope 3 at $DIR/lower_intrinsics.rs:+3:13: +3:15
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:13: +2:15
+          StorageLive(_4);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56
+          _4 = &raw const (*_1);           // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56
+-         _3 = option_payload_ptr::<usize>(move _4) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:99:18: 99:54
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<usize>) -> *const usize {option_payload_ptr::<usize>}, val: Value(<ZST>) }
++         _3 = &raw const (((*_4) as Some).0: usize); // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
++         goto -> bb1;                     // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
+      }
+  
+      bb1: {
+          StorageDead(_4);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:56: +2:57
+          StorageLive(_5);                 // scope 2 at $DIR/lower_intrinsics.rs:+3:13: +3:15
+          StorageLive(_6);                 // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56
+          _6 = &raw const (*_2);           // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56
+-         _5 = option_payload_ptr::<String>(move _6) -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:100:18: 100:54
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<String>) -> *const String {option_payload_ptr::<String>}, val: Value(<ZST>) }
++         _5 = &raw const (((*_6) as Some).0: std::string::String); // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
++         goto -> bb2;                     // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
+      }
+  
+      bb2: {
+          StorageDead(_6);                 // scope 2 at $DIR/lower_intrinsics.rs:+3:56: +3:57
+          _0 = const ();                   // scope 1 at $DIR/lower_intrinsics.rs:+1:5: +4:6
+          StorageDead(_5);                 // scope 2 at $DIR/lower_intrinsics.rs:+4:5: +4:6
+          StorageDead(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:+4:5: +4:6
+          return;                          // scope 0 at $DIR/lower_intrinsics.rs:+5:2: +5:2
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff
new file mode 100644
index 00000000000..27fceeedf6e
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff
@@ -0,0 +1,27 @@
+- // MIR for `read_via_copy_primitive` before LowerIntrinsics
++ // MIR for `read_via_copy_primitive` after LowerIntrinsics
+  
+  fn read_via_copy_primitive(_1: &i32) -> i32 {
+      debug r => _1;                       // in scope 0 at $DIR/lower_intrinsics.rs:+0:32: +0:33
+      let mut _0: i32;                     // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:44: +0:47
+      let mut _2: *const i32;              // in scope 0 at $DIR/lower_intrinsics.rs:+1:46: +1:47
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
+          _2 = &raw const (*_1);           // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
+-         _0 = read_via_copy::<i32>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:85:14: 85:45
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32) -> i32 {read_via_copy::<i32>}, val: Value(<ZST>) }
++         _0 = (*_2);                      // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
++         goto -> bb1;                     // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
+      }
+  
+      bb1: {
+          StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48
+          return;                          // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff
new file mode 100644
index 00000000000..610c67d2fec
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff
@@ -0,0 +1,21 @@
+- // MIR for `read_via_copy_uninhabited` before LowerIntrinsics
++ // MIR for `read_via_copy_uninhabited` after LowerIntrinsics
+  
+  fn read_via_copy_uninhabited(_1: &Never) -> Never {
+      debug r => _1;                       // in scope 0 at $DIR/lower_intrinsics.rs:+0:34: +0:35
+      let mut _0: Never;                   // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:48: +0:53
+      let mut _2: *const Never;            // in scope 0 at $DIR/lower_intrinsics.rs:+1:46: +1:47
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
+          _2 = &raw const (*_1);           // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
+-         _0 = read_via_copy::<Never>(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:90:14: 90:45
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Never) -> Never {read_via_copy::<Never>}, val: Value(<ZST>) }
++         unreachable;                     // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs
index 7147be43ca5..f07e2816f4f 100644
--- a/tests/mir-opt/lower_intrinsics.rs
+++ b/tests/mir-opt/lower_intrinsics.rs
@@ -79,3 +79,24 @@ pub fn with_overflow(a: i32, b: i32) {
     let _y = core::intrinsics::sub_with_overflow(a, b);
     let _z = core::intrinsics::mul_with_overflow(a, b);
 }
+
+// EMIT_MIR lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff
+pub fn read_via_copy_primitive(r: &i32) -> i32 {
+    unsafe { core::intrinsics::read_via_copy(r) }
+}
+
+// EMIT_MIR lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff
+pub fn read_via_copy_uninhabited(r: &Never) -> Never {
+    unsafe { core::intrinsics::read_via_copy(r) }
+}
+
+pub enum Never {}
+
+// EMIT_MIR lower_intrinsics.option_payload.LowerIntrinsics.diff
+#[cfg(not(bootstrap))]
+pub fn option_payload(o: &Option<usize>, p: &Option<String>) {
+    unsafe {
+        let _x = core::intrinsics::option_payload_ptr(o);
+        let _y = core::intrinsics::option_payload_ptr(p);
+    }
+}
diff --git a/tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir b/tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir
index f6d8bdd7422..adfc6b2731c 100644
--- a/tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir
+++ b/tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir
@@ -12,7 +12,6 @@ fn f_u64() -> () {
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21
-        StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21
         _2 = f_non_zst::<u64>(const 0_u64) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21
                                          // mir::Constant
                                          // + span: $DIR/lower_intrinsics_e2e.rs:23:9: 23:18
@@ -20,7 +19,6 @@ fn f_u64() -> () {
     }
 
     bb1: {
-        StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:21: 23:22
         StorageDead(_1);                 // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21
         return;                          // scope 0 at $DIR/lower_intrinsics_e2e.rs:+2:2: +2:2
     }
diff --git a/tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir b/tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir
index b672e1a6e63..302ca09aac4 100644
--- a/tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir
+++ b/tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir
@@ -2,26 +2,21 @@
 
 fn f_unit() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics_e2e.rs:+0:17: +0:17
-    let mut _1: ();                      // in scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:16: +1:18
     scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics_e2e.rs:9:5: 9:19
-        debug t => _1;                   // in scope 1 at $DIR/lower_intrinsics_e2e.rs:19:22: 19:23
-        let _2: ();                      // in scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
+        debug t => const ();             // in scope 1 at $DIR/lower_intrinsics_e2e.rs:19:22: 19:23
+        let _1: ();                      // in scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
         scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics_e2e.rs:20:8: 20:32
         }
     }
 
     bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:16: +1:18
-        StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
-        _2 = f_zst::<()>(move _1) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
+        _1 = f_zst::<()>(const ()) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
                                          // mir::Constant
                                          // + span: $DIR/lower_intrinsics_e2e.rs:21:9: 21:14
                                          // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value(<ZST>) }
     }
 
     bb1: {
-        StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:17: 21:18
-        StorageDead(_1);                 // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:18: +1:19
         return;                          // scope 0 at $DIR/lower_intrinsics_e2e.rs:+2:2: +2:2
     }
 }
diff --git a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff
index 07e4dd41813..7713649c5b9 100644
--- a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff
+++ b/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff
@@ -11,7 +11,7 @@
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12
+          nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12
           StorageLive(_3);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11
           _3 = move _1;                    // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11
           drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
@@ -23,7 +23,7 @@
   
       bb2: {
           StorageDead(_3);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:11: +1:12
-          StorageDead(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
+          nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
           nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+0:32: +2:2
           return;                          // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2
       }
diff --git a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff
index e809ca4e900..533db4051ef 100644
--- a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff
+++ b/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff
@@ -11,7 +11,7 @@
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12
+          nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12
           StorageLive(_3);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11
           _3 = move _1;                    // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11
           drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
@@ -23,7 +23,7 @@
   
       bb2: {
           StorageDead(_3);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:11: +1:12
-          StorageDead(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
+          nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
           nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+0:27: +2:2
           return;                          // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2
       }
diff --git a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff
index 087f76dbda8..04a2d54e9a1 100644
--- a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff
+++ b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff
@@ -11,7 +11,7 @@
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12
+-         nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12
           StorageLive(_3);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11
           _3 = _1;                         // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11
 -         drop(_3) -> bb1;                 // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
@@ -19,7 +19,7 @@
 - 
 -     bb1: {
           StorageDead(_3);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:11: +1:12
-          StorageDead(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
+-         nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
 -         nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+0:17: +2:2
           return;                          // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2
       }
diff --git a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff
index 933d6895f45..782d0c6c5f2 100644
--- a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff
+++ b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff
@@ -11,7 +11,7 @@
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12
+-         nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12
           StorageLive(_3);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11
           _3 = _1;                         // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11
 -         drop(_3) -> bb1;                 // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
@@ -19,7 +19,7 @@
 - 
 -     bb1: {
           StorageDead(_3);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:11: +1:12
-          StorageDead(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
+-         nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
 -         nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+0:36: +2:2
           return;                          // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2
       }
diff --git a/tests/mir-opt/remove_zsts.get_union.PreCodegen.after.mir b/tests/mir-opt/remove_zsts.get_union.PreCodegen.after.mir
index af34bc5edb7..7ac9ef3d490 100644
--- a/tests/mir-opt/remove_zsts.get_union.PreCodegen.after.mir
+++ b/tests/mir-opt/remove_zsts.get_union.PreCodegen.after.mir
@@ -2,12 +2,9 @@
 
 fn get_union() -> Foo {
     let mut _0: Foo;                     // return place in scope 0 at $DIR/remove_zsts.rs:+0:19: +0:22
-    let mut _1: ();                      // in scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
 
     bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
-        _0 = Foo { x: move _1 };         // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
-        StorageDead(_1);                 // scope 0 at $DIR/remove_zsts.rs:+1:17: +1:18
+        _0 = Foo { x: const () };        // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
         return;                          // scope 0 at $DIR/remove_zsts.rs:+2:2: +2:2
     }
 }
diff --git a/tests/mir-opt/remove_zsts.get_union.RemoveZsts.diff b/tests/mir-opt/remove_zsts.get_union.RemoveZsts.diff
index 0af29b2babc..edd86ef0aa9 100644
--- a/tests/mir-opt/remove_zsts.get_union.RemoveZsts.diff
+++ b/tests/mir-opt/remove_zsts.get_union.RemoveZsts.diff
@@ -6,11 +6,14 @@
       let mut _1: ();                      // in scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
+-         StorageLive(_1);                 // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
 -         _1 = ();                         // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
+-         _0 = Foo { x: move _1 };         // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
+-         StorageDead(_1);                 // scope 0 at $DIR/remove_zsts.rs:+1:17: +1:18
 +         nop;                             // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
-          _0 = Foo { x: move _1 };         // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
-          StorageDead(_1);                 // scope 0 at $DIR/remove_zsts.rs:+1:17: +1:18
++         nop;                             // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
++         _0 = Foo { x: const () };        // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
++         nop;                             // scope 0 at $DIR/remove_zsts.rs:+1:17: +1:18
           return;                          // scope 0 at $DIR/remove_zsts.rs:+2:2: +2:2
       }
   }
diff --git a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
index cfcd43093c0..bdf1de468b3 100644
--- a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
+++ b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
@@ -12,7 +12,6 @@
       let mut _7: !;                       // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
       let mut _8: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
       let _9: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      let mut _16: i32;                    // in scope 0 at $SRC_DIR/core/src/result.rs:LL:COL
       scope 1 {
           debug residual => _6;            // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
           scope 2 {
@@ -23,7 +22,7 @@
                   scope 9 {
                       debug e => _14;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
                       scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
-                          debug t => _16;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+                          debug t => _14;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
                       }
                   }
               }
@@ -90,10 +89,7 @@
           StorageLive(_14);                // scope 2 at $DIR/separate_const_switch.rs:+1:8: +1:10
           _14 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageLive(_15);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_16);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          _16 = move _14;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          _15 = move _16;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-          StorageDead(_16);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          _15 = move _14;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
           _0 = Result::<i32, i32>::Err(move _15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_15);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_14);                // scope 2 at $DIR/separate_const_switch.rs:+1:8: +1:10
diff --git a/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir b/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir
index 66ba4df767c..cae89fb177a 100644
--- a/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir
+++ b/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir
@@ -3,30 +3,28 @@
 fn ezmap(_1: Option<i32>) -> Option<i32> {
     debug x => _1;                       // in scope 0 at $DIR/simple_option_map_e2e.rs:+0:14: +0:15
     let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/simple_option_map_e2e.rs:+0:33: +0:44
-    let mut _2: [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]; // in scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
     scope 1 (inlined map::<i32, i32, [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]>) { // at $DIR/simple_option_map_e2e.rs:14:5: 14:22
         debug slf => _1;                 // in scope 1 at $DIR/simple_option_map_e2e.rs:2:17: 2:20
-        debug f => _2;                   // in scope 1 at $DIR/simple_option_map_e2e.rs:2:33: 2:34
-        let mut _3: isize;               // in scope 1 at $DIR/simple_option_map_e2e.rs:7:9: 7:16
-        let _4: i32;                     // in scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
-        let mut _5: i32;                 // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+        debug f => const ZeroSized: [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]; // in scope 1 at $DIR/simple_option_map_e2e.rs:2:33: 2:34
+        let mut _2: isize;               // in scope 1 at $DIR/simple_option_map_e2e.rs:7:9: 7:16
+        let _3: i32;                     // in scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+        let mut _4: i32;                 // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
         scope 2 {
-            debug x => _4;               // in scope 2 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+            debug x => _3;               // in scope 2 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
             scope 3 (inlined ezmap::{closure#0}) { // at $DIR/simple_option_map_e2e.rs:7:25: 7:29
-                debug n => _4;           // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14
+                debug n => _3;           // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14
             }
         }
     }
 
     bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
-        _3 = discriminant(_1);           // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
-        switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map_e2e.rs:6:5: 6:14
+        _2 = discriminant(_1);           // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
+        switchInt(move _2) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map_e2e.rs:6:5: 6:14
     }
 
     bb1: {
         _0 = Option::<i32>::None;        // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
-        goto -> bb4;                     // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+        return;                          // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
     }
 
     bb2: {
@@ -34,16 +32,11 @@ fn ezmap(_1: Option<i32>) -> Option<i32> {
     }
 
     bb3: {
-        _4 = ((_1 as Some).0: i32);      // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
-        StorageLive(_5);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
-        _5 = Add(_4, const 1_i32);       // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
-        _0 = Option::<i32>::Some(move _5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
-        StorageDead(_5);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30
-        goto -> bb4;                     // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2
-    }
-
-    bb4: {
-        StorageDead(_2);                 // scope 0 at $DIR/simple_option_map_e2e.rs:+1:21: +1:22
-        return;                          // scope 0 at $DIR/simple_option_map_e2e.rs:+2:2: +2:2
+        _3 = ((_1 as Some).0: i32);      // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+        StorageLive(_4);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+        _4 = Add(_3, const 1_i32);       // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
+        _0 = Option::<i32>::Some(move _4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+        StorageDead(_4);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30
+        return;                          // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2
     }
 }
diff --git a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
index f9e22866bee..ac79e727013 100644
--- a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
+++ b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
@@ -14,7 +14,6 @@
       }
   
       bb1: {
-          StorageLive(_2);                 // scope 0 at $DIR/simplify_if.rs:+2:9: +2:15
           _2 = noop() -> bb2;              // scope 0 at $DIR/simplify_if.rs:+2:9: +2:15
                                            // mir::Constant
                                            // + span: $DIR/simplify_if.rs:7:9: 7:13
@@ -22,7 +21,6 @@
       }
   
       bb2: {
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_if.rs:+2:15: +2:16
           goto -> bb4;                     // scope 0 at $DIR/simplify_if.rs:+1:5: +3:6
       }
   
diff --git a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
index 391b00effac..3884d29db41 100644
--- a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
+++ b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
@@ -4,21 +4,13 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
     let mut _0: ();                      // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     let mut _2: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     let mut _3: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _4: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _6: bool;                    // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _8: bool;                    // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _12: bool;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _14: bool;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _4: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _5: bool;                    // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _6: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _7: bool;                    // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
 
     bb0: {
-        goto -> bb15;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        goto -> bb8;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 
     bb1: {
@@ -30,72 +22,34 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
     }
 
     bb3 (cleanup): {
-        _5 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_5)) -> bb4;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _4 = &raw mut (*_1)[_3];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _3 = Add(move _3, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        drop((*_4)) -> bb4;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 
     bb4 (cleanup): {
-        _6 = Eq(_4, _3);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _6) -> [0: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _5 = Eq(_3, _2);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        switchInt(move _5) -> [0: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 
     bb5: {
-        _7 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _6 = &raw mut (*_1)[_3];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _3 = Add(move _3, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        drop((*_6)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 
     bb6: {
-        _8 = Eq(_4, _3);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _8) -> [0: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _7 = Eq(_3, _2);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        switchInt(move _7) -> [0: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 
     bb7: {
-        _4 = const 0_usize;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _2 = Len((*_1));                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _3 = const 0_usize;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
         goto -> bb6;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 
     bb8: {
         goto -> bb7;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
-
-    bb9 (cleanup): {
-        _11 = _9;                        // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_11)) -> bb10;            // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb10 (cleanup): {
-        _12 = Eq(_9, _10);               // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _12) -> [0: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb11: {
-        _13 = _9;                        // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb12: {
-        _14 = Eq(_9, _10);               // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _14) -> [0: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb13: {
-        _15 = &raw mut (*_1);            // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _9 = move _15 as *mut std::string::String (PtrToPtr); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _10 = Offset(_9, move _3);       // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        goto -> bb12;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb14: {
-        goto -> bb13;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb15: {
-        _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _3 = Len((*_1));                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _2) -> [0: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
 }
diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp
index e0fa1fe2824..4020a433d62 100644
--- a/tests/pretty/issue-4264.pp
+++ b/tests/pretty/issue-4264.pp
@@ -32,13 +32,11 @@ fn bar() ({
         ({
                 let res =
                     ((::alloc::fmt::format as
-                            for<'a> fn(Arguments<'a>) -> String {format})(((<#[lang = "format_arguments"]>::new_v1
+                            for<'a> fn(Arguments<'a>) -> String {format})(((<#[lang = "format_arguments"]>::new_const
                                 as
-                                fn(&[&'static str], &[core::fmt::ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test"
-                                            as &str)] as [&str; 1]) as &[&str; 1]),
-                            (&([] as [core::fmt::ArgumentV1<'_>; 0]) as
-                                &[core::fmt::ArgumentV1<'_>; 0])) as Arguments<'_>)) as
-                        String);
+                                fn(&[&'static str]) -> Arguments<'_> {Arguments::<'_>::new_const})((&([("test"
+                                            as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>))
+                        as String);
                 (res as String)
             } as String);
     } as ())
diff --git a/tests/pretty/tests-are-sorted.pp b/tests/pretty/tests-are-sorted.pp
index 15dcd4ed97d..58f746f2e0e 100644
--- a/tests/pretty/tests-are-sorted.pp
+++ b/tests/pretty/tests-are-sorted.pp
@@ -4,7 +4,7 @@
 use ::std::prelude::rust_2015::*;
 #[macro_use]
 extern crate std;
-// compile-flags: --crate-type=lib --test
+// compile-flags: --crate-type=lib --test --remap-path-prefix={{src-base}}/=/the/src/ --remap-path-prefix={{src-base}}\=/the/src/
 // pretty-compare-only
 // pretty-mode:expanded
 // pp-exact:tests-are-sorted.pp
@@ -18,6 +18,11 @@ pub const m_test: test::TestDescAndFn =
             name: test::StaticTestName("m_test"),
             ignore: false,
             ignore_message: ::core::option::Option::None,
+            source_file: "/the/src/tests-are-sorted.rs",
+            start_line: 7usize,
+            start_col: 4usize,
+            end_line: 7usize,
+            end_col: 10usize,
             compile_fail: false,
             no_run: false,
             should_panic: test::ShouldPanic::No,
@@ -34,8 +39,13 @@ pub const z_test: test::TestDescAndFn =
     test::TestDescAndFn {
         desc: test::TestDesc {
             name: test::StaticTestName("z_test"),
-            ignore: false,
-            ignore_message: ::core::option::Option::None,
+            ignore: true,
+            ignore_message: ::core::option::Option::Some("not yet implemented"),
+            source_file: "/the/src/tests-are-sorted.rs",
+            start_line: 11usize,
+            start_col: 4usize,
+            end_line: 11usize,
+            end_col: 10usize,
             compile_fail: false,
             no_run: false,
             should_panic: test::ShouldPanic::No,
@@ -43,6 +53,7 @@ pub const z_test: test::TestDescAndFn =
         },
         testfn: test::StaticTestFn(|| test::assert_test_result(z_test())),
     };
+#[ignore = "not yet implemented"]
 fn z_test() {}
 
 extern crate test;
@@ -54,6 +65,11 @@ pub const a_test: test::TestDescAndFn =
             name: test::StaticTestName("a_test"),
             ignore: false,
             ignore_message: ::core::option::Option::None,
+            source_file: "/the/src/tests-are-sorted.rs",
+            start_line: 14usize,
+            start_col: 4usize,
+            end_line: 14usize,
+            end_col: 10usize,
             compile_fail: false,
             no_run: false,
             should_panic: test::ShouldPanic::No,
diff --git a/tests/pretty/tests-are-sorted.rs b/tests/pretty/tests-are-sorted.rs
index 1f737d54719..39e0922250b 100644
--- a/tests/pretty/tests-are-sorted.rs
+++ b/tests/pretty/tests-are-sorted.rs
@@ -1,4 +1,4 @@
-// compile-flags: --crate-type=lib --test
+// compile-flags: --crate-type=lib --test --remap-path-prefix={{src-base}}/=/the/src/ --remap-path-prefix={{src-base}}\=/the/src/
 // pretty-compare-only
 // pretty-mode:expanded
 // pp-exact:tests-are-sorted.pp
@@ -7,6 +7,7 @@
 fn m_test() {}
 
 #[test]
+#[ignore = "not yet implemented"]
 fn z_test() {}
 
 #[test]
diff --git a/tests/run-make-fulldeps/tools.mk b/tests/run-make-fulldeps/tools.mk
index 0f5425daa16..ea06b620c4c 100644
--- a/tests/run-make-fulldeps/tools.mk
+++ b/tests/run-make-fulldeps/tools.mk
@@ -112,9 +112,9 @@ endif
 # Extra flags needed to compile a working executable with the standard library
 ifdef IS_WINDOWS
 ifdef IS_MSVC
-	EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib
+	EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib
 else
-	EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt
+	EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll
 	EXTRACXXFLAGS := -lstdc++
 	# So this is a bit hacky: we can't use the DLL version of libstdc++ because
 	# it pulls in the DLL version of libgcc, which means that we end up with 2
diff --git a/tests/rustdoc-js-std/option-type-signatures.js b/tests/rustdoc-js-std/option-type-signatures.js
index dee4819e81a..6bf421a2135 100644
--- a/tests/rustdoc-js-std/option-type-signatures.js
+++ b/tests/rustdoc-js-std/option-type-signatures.js
@@ -1,7 +1,18 @@
-const QUERY = 'option, fnonce -> option';
+const QUERY = [
+    'option, fnonce -> option',
+    'option -> default',
+];
 
-const EXPECTED = {
-    'others': [
-        { 'path': 'std::option::Option', 'name': 'map' },
-    ],
-};
+const EXPECTED = [
+    {
+        'others': [
+            { 'path': 'std::option::Option', 'name': 'map' },
+        ],
+    },
+    {
+        'others': [
+            { 'path': 'std::option::Option', 'name': 'unwrap_or_default' },
+            { 'path': 'std::option::Option', 'name': 'get_or_insert_default' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/search-bag-semantics.js b/tests/rustdoc-js/search-bag-semantics.js
new file mode 100644
index 00000000000..c56a3df5f90
--- /dev/null
+++ b/tests/rustdoc-js/search-bag-semantics.js
@@ -0,0 +1,20 @@
+// exact-check
+
+const QUERY = [
+    'P',
+    'P, P',
+];
+
+const EXPECTED = [
+    {
+        'in_args': [
+            { 'path': 'search_bag_semantics', 'name': 'alacazam' },
+            { 'path': 'search_bag_semantics', 'name': 'abracadabra' },
+        ],
+    },
+    {
+        'others': [
+            { 'path': 'search_bag_semantics', 'name': 'abracadabra' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/search-bag-semantics.rs b/tests/rustdoc-js/search-bag-semantics.rs
new file mode 100644
index 00000000000..546572dc4ef
--- /dev/null
+++ b/tests/rustdoc-js/search-bag-semantics.rs
@@ -0,0 +1,4 @@
+pub struct P;
+
+pub fn abracadabra(a: P, b: P) {}
+pub fn alacazam(a: P) {}
diff --git a/tests/rustdoc-js/where-clause.js b/tests/rustdoc-js/where-clause.js
index 6cb42a455a3..86254a80e20 100644
--- a/tests/rustdoc-js/where-clause.js
+++ b/tests/rustdoc-js/where-clause.js
@@ -1,4 +1,4 @@
-const QUERY = ['trait<nested>', '-> trait<nested>', 't1, t2'];
+const QUERY = ['trait<nested>', '-> trait<nested>', 't1, t2', '-> shazam', 'drizzel -> shazam'];
 
 const EXPECTED = [
     {
@@ -16,4 +16,15 @@ const EXPECTED = [
             { 'path': 'where_clause', 'name': 'presto' },
         ],
     },
+    {
+        'others': [
+            { 'path': 'where_clause', 'name': 'bippety' },
+            { 'path': 'where_clause::Drizzel', 'name': 'boppety' },
+        ],
+    },
+    {
+        'others': [
+            { 'path': 'where_clause::Drizzel', 'name': 'boppety' },
+        ],
+    },
 ];
diff --git a/tests/rustdoc-js/where-clause.rs b/tests/rustdoc-js/where-clause.rs
index 808561feee2..56c01019fb6 100644
--- a/tests/rustdoc-js/where-clause.rs
+++ b/tests/rustdoc-js/where-clause.rs
@@ -14,3 +14,17 @@ pub trait T2<'a, T> {
 }
 
 pub fn presto<A, B>(_: A, _: B) where A: T1, B: for <'b> T2<'b, Nested> {}
+
+pub trait Shazam {}
+
+pub fn bippety<X>() -> &'static X where X: Shazam {
+    panic!()
+}
+
+pub struct Drizzel<T>(T);
+
+impl<T> Drizzel<T> {
+    pub fn boppety(&self) -> &T where T: Shazam {
+        panic!();
+    }
+}
diff --git a/tests/rustdoc-json/fns/extern_c_variadic.rs b/tests/rustdoc-json/fns/extern_c_variadic.rs
new file mode 100644
index 00000000000..33bebbab5e0
--- /dev/null
+++ b/tests/rustdoc-json/fns/extern_c_variadic.rs
@@ -0,0 +1,9 @@
+#![feature(no_core)]
+#![no_core]
+
+extern "C" {
+    // @is "$.index[*][?(@.name == 'not_variadic')].inner.decl.c_variadic" false
+    pub fn not_variadic(_: i32);
+    // @is "$.index[*][?(@.name == 'variadic')].inner.decl.c_variadic" true
+    pub fn variadic(_: i32, ...);
+}
diff --git a/tests/rustdoc-ui/intra-doc/import-inline-merge.rs b/tests/rustdoc-ui/intra-doc/import-inline-merge.rs
new file mode 100644
index 00000000000..31fef032b0f
--- /dev/null
+++ b/tests/rustdoc-ui/intra-doc/import-inline-merge.rs
@@ -0,0 +1,16 @@
+// Import for `A` is inlined and doc comments on the import and `A` itself are merged.
+// After the merge they still have correct parent scopes to resolve both `[A]` and `[B]`.
+
+// check-pass
+
+#![allow(rustdoc::private_intra_doc_links)]
+
+mod m {
+    /// [B]
+    pub struct A {}
+
+    pub struct B {}
+}
+
+/// [A]
+pub use m::A;
diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout
index 79e6b94f1ac..5ad38e4fd98 100644
--- a/tests/rustdoc-ui/z-help.stdout
+++ b/tests/rustdoc-ui/z-help.stdout
@@ -44,6 +44,7 @@
     -Z             export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries
     -Z                 extra-const-ub-checks=val -- turns on more checks to detect const UB, which can be slow (default: no)
     -Z                           fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
+    -Z                   flatten-format-args=val -- flatten nested format_args!() and literals into a simplified format_args!() call (default: no)
     -Z            force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
     -Z                                  fuel=val -- set the optimization fuel quota for a crate
     -Z                     function-sections=val -- whether each function should go in its own section
diff --git a/tests/rustdoc/deprecated.rs b/tests/rustdoc/deprecated.rs
index 51860441b35..9c9c0945b8f 100644
--- a/tests/rustdoc/deprecated.rs
+++ b/tests/rustdoc/deprecated.rs
@@ -28,6 +28,6 @@ pub struct V;
 pub struct W;
 
 // @matches deprecated/struct.X.html '//*[@class="stab deprecated"]' \
-//      'Deprecated: shorthand reason$'
-#[deprecated = "shorthand reason"]
+//      'Deprecated: shorthand reason: code$'
+#[deprecated = "shorthand reason: `code`"]
 pub struct X;
diff --git a/tests/rustdoc/footnote-in-summary.rs b/tests/rustdoc/footnote-in-summary.rs
new file mode 100644
index 00000000000..e6ff5a7fd51
--- /dev/null
+++ b/tests/rustdoc/footnote-in-summary.rs
@@ -0,0 +1,17 @@
+// This test ensures that no footnote reference is generated inside
+// summary doc.
+
+#![crate_name = "foo"]
+
+// @has 'foo/index.html'
+// @has - '//*[@class="desc docblock-short"]' 'hello bla'
+// @!has - '//*[@class="desc docblock-short"]/sup' '1'
+
+// @has 'foo/struct.S.html'
+// @has - '//*[@class="docblock"]//sup' '1'
+// @has - '//*[@class="docblock"]' 'hello 1 bla'
+
+/// hello [^foot] bla
+///
+/// [^foot]: blabla
+pub struct S;
diff --git a/tests/rustdoc/intra-doc/prim-methods.rs b/tests/rustdoc/intra-doc/prim-methods.rs
index a412a23fda8..bc1965aac55 100644
--- a/tests/rustdoc/intra-doc/prim-methods.rs
+++ b/tests/rustdoc/intra-doc/prim-methods.rs
@@ -2,6 +2,8 @@
 
 // @has prim_methods/index.html
 // @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html"]/@title' 'primitive char'
 // @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]/@title' 'method char::len_utf8'
 
 //! A [`char`] and its [`char::len_utf8`].
diff --git a/tests/rustdoc/issue-109258-missing-private-inlining.rs b/tests/rustdoc/issue-109258-missing-private-inlining.rs
new file mode 100644
index 00000000000..96f606368b2
--- /dev/null
+++ b/tests/rustdoc/issue-109258-missing-private-inlining.rs
@@ -0,0 +1,27 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/109258>.
+
+#![crate_name = "foo"]
+
+// @has 'foo/index.html'
+// We should only have a "Re-exports" and a "Modules" headers.
+// @count - '//*[@id="main-content"]/h2[@class="small-section-header"]' 2
+// @has - '//*[@id="main-content"]/h2[@class="small-section-header"]' 'Re-exports'
+// @has - '//*[@id="main-content"]/h2[@class="small-section-header"]' 'Modules'
+
+// @has - '//*[@id="reexport.Foo"]' 'pub use crate::issue_109258::Foo;'
+// @has - '//*[@id="reexport.Foo"]//a[@href="issue_109258/struct.Foo.html"]' 'Foo'
+// @!has 'foo/struct.Foo.html'
+pub use crate::issue_109258::Foo;
+
+// @has 'foo/issue_109258/index.html'
+// We should only have a "Structs" header.
+// @count - '//*[@id="main-content"]/h2[@class="small-section-header"]' 1
+// @has - '//*[@id="main-content"]/h2[@class="small-section-header"]' 'Structs'
+// @has - '//*[@id="main-content"]//a[@href="struct.Foo.html"]' 'Foo'
+// @has 'foo/issue_109258/struct.Foo.html'
+pub mod issue_109258 {
+    mod priv_mod {
+        pub struct Foo;
+    }
+    pub use self::priv_mod::Foo;
+}
diff --git a/tests/ui/associated-consts/issue-93775.rs b/tests/ui/associated-consts/issue-93775.rs
index 7a007b732de..db788fe6e6a 100644
--- a/tests/ui/associated-consts/issue-93775.rs
+++ b/tests/ui/associated-consts/issue-93775.rs
@@ -3,7 +3,7 @@
 
 // Regression for #93775, needs build-pass to test it.
 
-#![recursion_limit = "1000"]
+#![recursion_limit = "1001"]
 
 use std::marker::PhantomData;
 
diff --git a/tests/ui/async-await/async-trait-fn.current.stderr b/tests/ui/async-await/async-trait-fn.current.stderr
new file mode 100644
index 00000000000..7ccf2f2301d
--- /dev/null
+++ b/tests/ui/async-await/async-trait-fn.current.stderr
@@ -0,0 +1,42 @@
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/async-trait-fn.rs:6:5
+   |
+LL |     async fn foo() {}
+   |     -----^^^^^^^^^
+   |     |
+   |     `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/async-trait-fn.rs:7:5
+   |
+LL |     async fn bar(&self) {}
+   |     -----^^^^^^^^^^^^^^
+   |     |
+   |     `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/async-trait-fn.rs:8:5
+   |
+LL |     async fn baz() {
+   |     -----^^^^^^^^^
+   |     |
+   |     `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0706`.
diff --git a/tests/ui/async-await/async-trait-fn.next.stderr b/tests/ui/async-await/async-trait-fn.next.stderr
new file mode 100644
index 00000000000..7ccf2f2301d
--- /dev/null
+++ b/tests/ui/async-await/async-trait-fn.next.stderr
@@ -0,0 +1,42 @@
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/async-trait-fn.rs:6:5
+   |
+LL |     async fn foo() {}
+   |     -----^^^^^^^^^
+   |     |
+   |     `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/async-trait-fn.rs:7:5
+   |
+LL |     async fn bar(&self) {}
+   |     -----^^^^^^^^^^^^^^
+   |     |
+   |     `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/async-trait-fn.rs:8:5
+   |
+LL |     async fn baz() {
+   |     -----^^^^^^^^^
+   |     |
+   |     `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0706`.
diff --git a/tests/ui/async-await/async-trait-fn.rs b/tests/ui/async-await/async-trait-fn.rs
index e2062e82725..04123badb53 100644
--- a/tests/ui/async-await/async-trait-fn.rs
+++ b/tests/ui/async-await/async-trait-fn.rs
@@ -1,4 +1,5 @@
 // edition:2018
+
 trait T {
     async fn foo() {} //~ ERROR functions in traits cannot be declared `async`
     async fn bar(&self) {} //~ ERROR functions in traits cannot be declared `async`
diff --git a/tests/ui/async-await/async-trait-fn.stderr b/tests/ui/async-await/async-trait-fn.stderr
index afbe25cf7ab..68ebe3507ac 100644
--- a/tests/ui/async-await/async-trait-fn.stderr
+++ b/tests/ui/async-await/async-trait-fn.stderr
@@ -1,5 +1,5 @@
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/async-trait-fn.rs:3:5
+  --> $DIR/async-trait-fn.rs:4:5
    |
 LL |     async fn foo() {}
    |     -----^^^^^^^^^
@@ -12,7 +12,7 @@ LL |     async fn foo() {}
    = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/async-trait-fn.rs:4:5
+  --> $DIR/async-trait-fn.rs:5:5
    |
 LL |     async fn bar(&self) {}
    |     -----^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL |     async fn bar(&self) {}
    = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/async-trait-fn.rs:5:5
+  --> $DIR/async-trait-fn.rs:6:5
    |
 LL |     async fn baz() {
    |     -----^^^^^^^^^
diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.stderr b/tests/ui/async-await/edition-deny-async-fns-2015.current.stderr
index ba918eb28de..c47b99e657e 100644
--- a/tests/ui/async-await/edition-deny-async-fns-2015.stderr
+++ b/tests/ui/async-await/edition-deny-async-fns-2015.current.stderr
@@ -1,5 +1,5 @@
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:3:1
+  --> $DIR/edition-deny-async-fns-2015.rs:5:1
    |
 LL | async fn foo() {}
    | ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -8,7 +8,7 @@ LL | async fn foo() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:5:12
+  --> $DIR/edition-deny-async-fns-2015.rs:7:12
    |
 LL | fn baz() { async fn foo() {} }
    |            ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -17,7 +17,7 @@ LL | fn baz() { async fn foo() {} }
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:7:1
+  --> $DIR/edition-deny-async-fns-2015.rs:9:1
    |
 LL | async fn async_baz() {
    | ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -26,7 +26,7 @@ LL | async fn async_baz() {
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:8:5
+  --> $DIR/edition-deny-async-fns-2015.rs:10:5
    |
 LL |     async fn bar() {}
    |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -35,7 +35,7 @@ LL |     async fn bar() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:14:5
+  --> $DIR/edition-deny-async-fns-2015.rs:16:5
    |
 LL |     async fn foo() {}
    |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -44,7 +44,7 @@ LL |     async fn foo() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:18:5
+  --> $DIR/edition-deny-async-fns-2015.rs:20:5
    |
 LL |     async fn foo() {}
    |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -53,7 +53,7 @@ LL |     async fn foo() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:36:9
+  --> $DIR/edition-deny-async-fns-2015.rs:38:9
    |
 LL |         async fn bar() {}
    |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -62,7 +62,7 @@ LL |         async fn bar() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:26:9
+  --> $DIR/edition-deny-async-fns-2015.rs:28:9
    |
 LL |         async fn foo() {}
    |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -71,7 +71,7 @@ LL |         async fn foo() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:31:13
+  --> $DIR/edition-deny-async-fns-2015.rs:33:13
    |
 LL |             async fn bar() {}
    |             ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -80,7 +80,7 @@ LL |             async fn bar() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/edition-deny-async-fns-2015.rs:18:5
+  --> $DIR/edition-deny-async-fns-2015.rs:20:5
    |
 LL |     async fn foo() {}
    |     -----^^^^^^^^^
diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr b/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr
new file mode 100644
index 00000000000..c47b99e657e
--- /dev/null
+++ b/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr
@@ -0,0 +1,98 @@
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/edition-deny-async-fns-2015.rs:5:1
+   |
+LL | async fn foo() {}
+   | ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/edition-deny-async-fns-2015.rs:7:12
+   |
+LL | fn baz() { async fn foo() {} }
+   |            ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/edition-deny-async-fns-2015.rs:9:1
+   |
+LL | async fn async_baz() {
+   | ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/edition-deny-async-fns-2015.rs:10:5
+   |
+LL |     async fn bar() {}
+   |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/edition-deny-async-fns-2015.rs:16:5
+   |
+LL |     async fn foo() {}
+   |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/edition-deny-async-fns-2015.rs:20:5
+   |
+LL |     async fn foo() {}
+   |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/edition-deny-async-fns-2015.rs:38:9
+   |
+LL |         async fn bar() {}
+   |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/edition-deny-async-fns-2015.rs:28:9
+   |
+LL |         async fn foo() {}
+   |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/edition-deny-async-fns-2015.rs:33:13
+   |
+LL |             async fn bar() {}
+   |             ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/edition-deny-async-fns-2015.rs:20:5
+   |
+LL |     async fn foo() {}
+   |     -----^^^^^^^^^
+   |     |
+   |     `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0670, E0706.
+For more information about an error, try `rustc --explain E0670`.
diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.rs b/tests/ui/async-await/edition-deny-async-fns-2015.rs
index 6bd6d879a4a..d4c30dc9d82 100644
--- a/tests/ui/async-await/edition-deny-async-fns-2015.rs
+++ b/tests/ui/async-await/edition-deny-async-fns-2015.rs
@@ -1,4 +1,6 @@
 // edition:2015
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015
 
diff --git a/tests/ui/async-await/generator-desc.stderr b/tests/ui/async-await/generator-desc.stderr
index 51ac9d86bfb..042766f19ca 100644
--- a/tests/ui/async-await/generator-desc.stderr
+++ b/tests/ui/async-await/generator-desc.stderr
@@ -2,16 +2,18 @@ error[E0308]: mismatched types
   --> $DIR/generator-desc.rs:10:19
    |
 LL |     fun(async {}, async {});
-   |         --------  ^^^^^^^^
-   |         |         |
-   |         |         expected `async` block, found a different `async` block
-   |         |         arguments to this function are incorrect
-   |         the expected `async` block
+   |     --- --------  ^^^^^^^^ expected `async` block, found a different `async` block
+   |     |   |
+   |     |   the expected `async` block
+   |     arguments to this function are incorrect
    |
    = note: expected `async` block `[async block@$DIR/generator-desc.rs:10:9: 10:17]`
               found `async` block `[async block@$DIR/generator-desc.rs:10:19: 10:27]`
 note: function defined here
-  --> $SRC_DIR/core/src/future/mod.rs:LL:COL
+  --> $DIR/generator-desc.rs:8:4
+   |
+LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
+   |    ^^^                                -----
 
 error[E0308]: mismatched types
   --> $DIR/generator-desc.rs:12:16
diff --git a/tests/ui/async-await/in-trait/async-associated-types.rs b/tests/ui/async-await/in-trait/async-associated-types.rs
index 974f5aaff83..89ca4039bce 100644
--- a/tests/ui/async-await/in-trait/async-associated-types.rs
+++ b/tests/ui/async-await/in-trait/async-associated-types.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![feature(impl_trait_projections)]
diff --git a/tests/ui/async-await/in-trait/async-associated-types2.rs b/tests/ui/async-await/in-trait/async-associated-types2.rs
index e546a0579c6..cdecb02bfad 100644
--- a/tests/ui/async-await/in-trait/async-associated-types2.rs
+++ b/tests/ui/async-await/in-trait/async-associated-types2.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![feature(type_alias_impl_trait)]
diff --git a/tests/ui/async-await/in-trait/async-default-fn-overridden.stderr b/tests/ui/async-await/in-trait/async-default-fn-overridden.current.stderr
index 61a826258d0..2142ee232ca 100644
--- a/tests/ui/async-await/in-trait/async-default-fn-overridden.stderr
+++ b/tests/ui/async-await/in-trait/async-default-fn-overridden.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/async-default-fn-overridden.rs:4:12
+  --> $DIR/async-default-fn-overridden.rs:6:12
    |
 LL | #![feature(async_fn_in_trait)]
    |            ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/async-await/in-trait/async-default-fn-overridden.next.stderr b/tests/ui/async-await/in-trait/async-default-fn-overridden.next.stderr
new file mode 100644
index 00000000000..2142ee232ca
--- /dev/null
+++ b/tests/ui/async-await/in-trait/async-default-fn-overridden.next.stderr
@@ -0,0 +1,11 @@
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/async-default-fn-overridden.rs:6:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/async-await/in-trait/async-default-fn-overridden.rs b/tests/ui/async-await/in-trait/async-default-fn-overridden.rs
index 0fd1a2703db..dd1af93d706 100644
--- a/tests/ui/async-await/in-trait/async-default-fn-overridden.rs
+++ b/tests/ui/async-await/in-trait/async-default-fn-overridden.rs
@@ -1,5 +1,7 @@
 // run-pass
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.current.stderr
index 168ef8e9ee4..b5ace9ada4f 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.current.stderr
@@ -1,11 +1,11 @@
 error[E0053]: method `foo` has an incompatible type for trait
-  --> $DIR/async-example-desugared-boxed-in-trait.rs:15:28
+  --> $DIR/async-example-desugared-boxed-in-trait.rs:17:28
    |
 LL |     async fn foo(&self) -> i32 {
    |                            ^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future
    |
 note: type in trait
-  --> $DIR/async-example-desugared-boxed-in-trait.rs:11:22
+  --> $DIR/async-example-desugared-boxed-in-trait.rs:13:22
    |
 LL |     fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.next.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.next.stderr
new file mode 100644
index 00000000000..b5ace9ada4f
--- /dev/null
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.next.stderr
@@ -0,0 +1,17 @@
+error[E0053]: method `foo` has an incompatible type for trait
+  --> $DIR/async-example-desugared-boxed-in-trait.rs:17:28
+   |
+LL |     async fn foo(&self) -> i32 {
+   |                            ^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future
+   |
+note: type in trait
+  --> $DIR/async-example-desugared-boxed-in-trait.rs:13:22
+   |
+LL |     fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected signature `fn(&i32) -> Pin<Box<dyn Future<Output = i32>>>`
+              found signature `fn(&i32) -> impl Future<Output = i32>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs
index 38ba297189c..7b53379b24b 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs
@@ -1,4 +1,6 @@
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![feature(return_position_impl_trait_in_trait)]
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed.current.stderr
index 60fa534a64f..6c0b5859186 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed.current.stderr
@@ -1,5 +1,5 @@
 error: method `foo` should be async because the method from the trait is async
-  --> $DIR/async-example-desugared-boxed.rs:15:5
+  --> $DIR/async-example-desugared-boxed.rs:17:5
    |
 LL |     async fn foo(&self) -> i32;
    |     --------------------------- required because the trait method is async
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed.next.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed.next.stderr
new file mode 100644
index 00000000000..6c0b5859186
--- /dev/null
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed.next.stderr
@@ -0,0 +1,11 @@
+error: method `foo` should be async because the method from the trait is async
+  --> $DIR/async-example-desugared-boxed.rs:17:5
+   |
+LL |     async fn foo(&self) -> i32;
+   |     --------------------------- required because the trait method is async
+...
+LL |     fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs b/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs
index 1b1b3cffd58..916488ffafa 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs
@@ -1,4 +1,6 @@
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![feature(return_position_impl_trait_in_trait)]
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs
index 81e1e59a362..edac0b374a3 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![feature(return_position_impl_trait_in_trait)]
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs b/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs
index feeda719e03..934f7643dd1 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![feature(return_position_impl_trait_in_trait)]
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr b/tests/ui/async-await/in-trait/async-example-desugared-manual.current.stderr
index 567a36a86d1..0d2551ab84f 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr
+++ b/tests/ui/async-await/in-trait/async-example-desugared-manual.current.stderr
@@ -1,5 +1,5 @@
 error: method `foo` should be async because the method from the trait is async
-  --> $DIR/async-example-desugared-manual.rs:23:5
+  --> $DIR/async-example-desugared-manual.rs:25:5
    |
 LL |     async fn foo(&self) -> i32;
    |     --------------------------- required because the trait method is async
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-manual.next.stderr b/tests/ui/async-await/in-trait/async-example-desugared-manual.next.stderr
new file mode 100644
index 00000000000..0d2551ab84f
--- /dev/null
+++ b/tests/ui/async-await/in-trait/async-example-desugared-manual.next.stderr
@@ -0,0 +1,11 @@
+error: method `foo` should be async because the method from the trait is async
+  --> $DIR/async-example-desugared-manual.rs:25:5
+   |
+LL |     async fn foo(&self) -> i32;
+   |     --------------------------- required because the trait method is async
+...
+LL |     fn foo(&self) -> MyFuture {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-manual.rs b/tests/ui/async-await/in-trait/async-example-desugared-manual.rs
index 71473e7455f..4883828d32f 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-manual.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-manual.rs
@@ -1,4 +1,6 @@
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![feature(return_position_impl_trait_in_trait)]
diff --git a/tests/ui/async-await/in-trait/async-example-desugared.rs b/tests/ui/async-await/in-trait/async-example-desugared.rs
index fb92ec78674..214171b2e2c 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![feature(return_position_impl_trait_in_trait)]
diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.current.stderr
index f1f0d7e5907..780da068962 100644
--- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
+++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.current.stderr
@@ -1,33 +1,33 @@
 error[E0311]: the parameter type `U` may not live long enough
-  --> $DIR/async-generics-and-bounds.rs:12:28
+  --> $DIR/async-generics-and-bounds.rs:14:28
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |                            ^^^^^^^
    |
 note: the parameter type `U` must be valid for the anonymous lifetime defined here...
-  --> $DIR/async-generics-and-bounds.rs:12:18
+  --> $DIR/async-generics-and-bounds.rs:14:18
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |                  ^^^^^
 note: ...so that the reference type `&(T, U)` does not outlive the data it points at
-  --> $DIR/async-generics-and-bounds.rs:12:28
+  --> $DIR/async-generics-and-bounds.rs:14:28
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |                            ^^^^^^^
 
 error[E0311]: the parameter type `T` may not live long enough
-  --> $DIR/async-generics-and-bounds.rs:12:28
+  --> $DIR/async-generics-and-bounds.rs:14:28
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |                            ^^^^^^^
    |
 note: the parameter type `T` must be valid for the anonymous lifetime defined here...
-  --> $DIR/async-generics-and-bounds.rs:12:18
+  --> $DIR/async-generics-and-bounds.rs:14:18
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |                  ^^^^^
 note: ...so that the reference type `&(T, U)` does not outlive the data it points at
-  --> $DIR/async-generics-and-bounds.rs:12:28
+  --> $DIR/async-generics-and-bounds.rs:14:28
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |                            ^^^^^^^
diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.next.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.next.stderr
new file mode 100644
index 00000000000..780da068962
--- /dev/null
+++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.next.stderr
@@ -0,0 +1,37 @@
+error[E0311]: the parameter type `U` may not live long enough
+  --> $DIR/async-generics-and-bounds.rs:14:28
+   |
+LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+   |                            ^^^^^^^
+   |
+note: the parameter type `U` must be valid for the anonymous lifetime defined here...
+  --> $DIR/async-generics-and-bounds.rs:14:18
+   |
+LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+   |                  ^^^^^
+note: ...so that the reference type `&(T, U)` does not outlive the data it points at
+  --> $DIR/async-generics-and-bounds.rs:14:28
+   |
+LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+   |                            ^^^^^^^
+
+error[E0311]: the parameter type `T` may not live long enough
+  --> $DIR/async-generics-and-bounds.rs:14:28
+   |
+LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+   |                            ^^^^^^^
+   |
+note: the parameter type `T` must be valid for the anonymous lifetime defined here...
+  --> $DIR/async-generics-and-bounds.rs:14:18
+   |
+LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+   |                  ^^^^^
+note: ...so that the reference type `&(T, U)` does not outlive the data it points at
+  --> $DIR/async-generics-and-bounds.rs:14:28
+   |
+LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+   |                            ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0311`.
diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs
index a73d55adfec..146e74ec2d0 100644
--- a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs
+++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs
@@ -1,6 +1,8 @@
 // check-fail
 // known-bug: #102682
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.current.stderr
index 2f05564564c..04e1ab6d769 100644
--- a/tests/ui/async-await/in-trait/async-generics.stderr
+++ b/tests/ui/async-await/in-trait/async-generics.current.stderr
@@ -1,33 +1,33 @@
 error[E0311]: the parameter type `U` may not live long enough
-  --> $DIR/async-generics.rs:9:28
+  --> $DIR/async-generics.rs:11:28
    |
 LL |     async fn foo(&self) -> &(T, U);
    |                            ^^^^^^^
    |
 note: the parameter type `U` must be valid for the anonymous lifetime defined here...
-  --> $DIR/async-generics.rs:9:18
+  --> $DIR/async-generics.rs:11:18
    |
 LL |     async fn foo(&self) -> &(T, U);
    |                  ^^^^^
 note: ...so that the reference type `&(T, U)` does not outlive the data it points at
-  --> $DIR/async-generics.rs:9:28
+  --> $DIR/async-generics.rs:11:28
    |
 LL |     async fn foo(&self) -> &(T, U);
    |                            ^^^^^^^
 
 error[E0311]: the parameter type `T` may not live long enough
-  --> $DIR/async-generics.rs:9:28
+  --> $DIR/async-generics.rs:11:28
    |
 LL |     async fn foo(&self) -> &(T, U);
    |                            ^^^^^^^
    |
 note: the parameter type `T` must be valid for the anonymous lifetime defined here...
-  --> $DIR/async-generics.rs:9:18
+  --> $DIR/async-generics.rs:11:18
    |
 LL |     async fn foo(&self) -> &(T, U);
    |                  ^^^^^
 note: ...so that the reference type `&(T, U)` does not outlive the data it points at
-  --> $DIR/async-generics.rs:9:28
+  --> $DIR/async-generics.rs:11:28
    |
 LL |     async fn foo(&self) -> &(T, U);
    |                            ^^^^^^^
diff --git a/tests/ui/async-await/in-trait/async-generics.next.stderr b/tests/ui/async-await/in-trait/async-generics.next.stderr
new file mode 100644
index 00000000000..04e1ab6d769
--- /dev/null
+++ b/tests/ui/async-await/in-trait/async-generics.next.stderr
@@ -0,0 +1,37 @@
+error[E0311]: the parameter type `U` may not live long enough
+  --> $DIR/async-generics.rs:11:28
+   |
+LL |     async fn foo(&self) -> &(T, U);
+   |                            ^^^^^^^
+   |
+note: the parameter type `U` must be valid for the anonymous lifetime defined here...
+  --> $DIR/async-generics.rs:11:18
+   |
+LL |     async fn foo(&self) -> &(T, U);
+   |                  ^^^^^
+note: ...so that the reference type `&(T, U)` does not outlive the data it points at
+  --> $DIR/async-generics.rs:11:28
+   |
+LL |     async fn foo(&self) -> &(T, U);
+   |                            ^^^^^^^
+
+error[E0311]: the parameter type `T` may not live long enough
+  --> $DIR/async-generics.rs:11:28
+   |
+LL |     async fn foo(&self) -> &(T, U);
+   |                            ^^^^^^^
+   |
+note: the parameter type `T` must be valid for the anonymous lifetime defined here...
+  --> $DIR/async-generics.rs:11:18
+   |
+LL |     async fn foo(&self) -> &(T, U);
+   |                  ^^^^^
+note: ...so that the reference type `&(T, U)` does not outlive the data it points at
+  --> $DIR/async-generics.rs:11:28
+   |
+LL |     async fn foo(&self) -> &(T, U);
+   |                            ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0311`.
diff --git a/tests/ui/async-await/in-trait/async-generics.rs b/tests/ui/async-await/in-trait/async-generics.rs
index 67000e5770e..507500abf4e 100644
--- a/tests/ui/async-await/in-trait/async-generics.rs
+++ b/tests/ui/async-await/in-trait/async-generics.rs
@@ -1,6 +1,8 @@
 // check-fail
 // known-bug: #102682
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.stderr b/tests/ui/async-await/in-trait/async-recursive-generic.current.stderr
index cab173bdd5b..67b491f19d2 100644
--- a/tests/ui/async-await/in-trait/async-recursive-generic.stderr
+++ b/tests/ui/async-await/in-trait/async-recursive-generic.current.stderr
@@ -1,5 +1,5 @@
 error[E0733]: recursion in an `async fn` requires boxing
-  --> $DIR/async-recursive-generic.rs:11:48
+  --> $DIR/async-recursive-generic.rs:13:48
    |
 LL |     async fn foo_recursive(&self, n: usize) -> T {
    |                                                ^ recursive `async fn`
diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.next.stderr b/tests/ui/async-await/in-trait/async-recursive-generic.next.stderr
new file mode 100644
index 00000000000..67b491f19d2
--- /dev/null
+++ b/tests/ui/async-await/in-trait/async-recursive-generic.next.stderr
@@ -0,0 +1,12 @@
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/async-recursive-generic.rs:13:48
+   |
+LL |     async fn foo_recursive(&self, n: usize) -> T {
+   |                                                ^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0733`.
diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.rs b/tests/ui/async-await/in-trait/async-recursive-generic.rs
index 6839abd381c..64c6ba15c0c 100644
--- a/tests/ui/async-await/in-trait/async-recursive-generic.rs
+++ b/tests/ui/async-await/in-trait/async-recursive-generic.rs
@@ -1,4 +1,6 @@
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/async-await/in-trait/async-recursive.stderr b/tests/ui/async-await/in-trait/async-recursive.current.stderr
index 9feff37b3fe..85af27e3746 100644
--- a/tests/ui/async-await/in-trait/async-recursive.stderr
+++ b/tests/ui/async-await/in-trait/async-recursive.current.stderr
@@ -1,5 +1,5 @@
 error[E0733]: recursion in an `async fn` requires boxing
-  --> $DIR/async-recursive.rs:11:48
+  --> $DIR/async-recursive.rs:13:48
    |
 LL |     async fn foo_recursive(&self, n: usize) -> i32 {
    |                                                ^^^ recursive `async fn`
diff --git a/tests/ui/async-await/in-trait/async-recursive.next.stderr b/tests/ui/async-await/in-trait/async-recursive.next.stderr
new file mode 100644
index 00000000000..85af27e3746
--- /dev/null
+++ b/tests/ui/async-await/in-trait/async-recursive.next.stderr
@@ -0,0 +1,12 @@
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/async-recursive.rs:13:48
+   |
+LL |     async fn foo_recursive(&self, n: usize) -> i32 {
+   |                                                ^^^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0733`.
diff --git a/tests/ui/async-await/in-trait/async-recursive.rs b/tests/ui/async-await/in-trait/async-recursive.rs
index 61119f8095b..d928909e3ae 100644
--- a/tests/ui/async-await/in-trait/async-recursive.rs
+++ b/tests/ui/async-await/in-trait/async-recursive.rs
@@ -1,4 +1,6 @@
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/async-await/in-trait/bad-signatures.stderr b/tests/ui/async-await/in-trait/bad-signatures.current.stderr
index e0ba7b53ec4..5a05b080c3e 100644
--- a/tests/ui/async-await/in-trait/bad-signatures.stderr
+++ b/tests/ui/async-await/in-trait/bad-signatures.current.stderr
@@ -1,11 +1,11 @@
 error: expected identifier, found keyword `self`
-  --> $DIR/bad-signatures.rs:7:23
+  --> $DIR/bad-signatures.rs:9:23
    |
 LL |     async fn bar(&abc self);
    |                       ^^^^ expected identifier, found keyword
 
 error: expected one of `:`, `@`, or `|`, found keyword `self`
-  --> $DIR/bad-signatures.rs:7:23
+  --> $DIR/bad-signatures.rs:9:23
    |
 LL |     async fn bar(&abc self);
    |                  -----^^^^
@@ -14,7 +14,7 @@ LL |     async fn bar(&abc self);
    |                  help: declare the type after the parameter binding: `<identifier>: <type>`
 
 warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/bad-signatures.rs:3:12
+  --> $DIR/bad-signatures.rs:5:12
    |
 LL | #![feature(async_fn_in_trait)]
    |            ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/async-await/in-trait/bad-signatures.next.stderr b/tests/ui/async-await/in-trait/bad-signatures.next.stderr
new file mode 100644
index 00000000000..5a05b080c3e
--- /dev/null
+++ b/tests/ui/async-await/in-trait/bad-signatures.next.stderr
@@ -0,0 +1,26 @@
+error: expected identifier, found keyword `self`
+  --> $DIR/bad-signatures.rs:9:23
+   |
+LL |     async fn bar(&abc self);
+   |                       ^^^^ expected identifier, found keyword
+
+error: expected one of `:`, `@`, or `|`, found keyword `self`
+  --> $DIR/bad-signatures.rs:9:23
+   |
+LL |     async fn bar(&abc self);
+   |                  -----^^^^
+   |                  |    |
+   |                  |    expected one of `:`, `@`, or `|`
+   |                  help: declare the type after the parameter binding: `<identifier>: <type>`
+
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/bad-signatures.rs:5:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
diff --git a/tests/ui/async-await/in-trait/bad-signatures.rs b/tests/ui/async-await/in-trait/bad-signatures.rs
index b86f1d1c135..e0093be8cb3 100644
--- a/tests/ui/async-await/in-trait/bad-signatures.rs
+++ b/tests/ui/async-await/in-trait/bad-signatures.rs
@@ -1,4 +1,6 @@
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 //~^ WARN the feature `async_fn_in_trait` is incomplete
diff --git a/tests/ui/async-await/in-trait/early-bound-1.rs b/tests/ui/async-await/in-trait/early-bound-1.rs
index 6b3b142014b..30843473def 100644
--- a/tests/ui/async-await/in-trait/early-bound-1.rs
+++ b/tests/ui/async-await/in-trait/early-bound-1.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/async-await/in-trait/early-bound-2.rs b/tests/ui/async-await/in-trait/early-bound-2.rs
index 270443229b0..1c5a68c2a5a 100644
--- a/tests/ui/async-await/in-trait/early-bound-2.rs
+++ b/tests/ui/async-await/in-trait/early-bound-2.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/async-await/in-trait/fn-not-async-err2.stderr b/tests/ui/async-await/in-trait/fn-not-async-err2.current.stderr
index 37d9669c012..1a749514989 100644
--- a/tests/ui/async-await/in-trait/fn-not-async-err2.stderr
+++ b/tests/ui/async-await/in-trait/fn-not-async-err2.current.stderr
@@ -1,5 +1,5 @@
 error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return types
-  --> $DIR/fn-not-async-err2.rs:13:22
+  --> $DIR/fn-not-async-err2.rs:15:22
    |
 LL |     fn foo(&self) -> impl Future<Output = i32> {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/async-await/in-trait/fn-not-async-err2.next.stderr b/tests/ui/async-await/in-trait/fn-not-async-err2.next.stderr
new file mode 100644
index 00000000000..1a749514989
--- /dev/null
+++ b/tests/ui/async-await/in-trait/fn-not-async-err2.next.stderr
@@ -0,0 +1,12 @@
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return types
+  --> $DIR/fn-not-async-err2.rs:15:22
+   |
+LL |     fn foo(&self) -> impl Future<Output = i32> {
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/async-await/in-trait/fn-not-async-err2.rs b/tests/ui/async-await/in-trait/fn-not-async-err2.rs
index 78017429f73..5fdb7296aaf 100644
--- a/tests/ui/async-await/in-trait/fn-not-async-err2.rs
+++ b/tests/ui/async-await/in-trait/fn-not-async-err2.rs
@@ -1,4 +1,6 @@
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/async-await/in-trait/generics-mismatch.current.stderr b/tests/ui/async-await/in-trait/generics-mismatch.current.stderr
new file mode 100644
index 00000000000..be23384e049
--- /dev/null
+++ b/tests/ui/async-await/in-trait/generics-mismatch.current.stderr
@@ -0,0 +1,16 @@
+error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo`
+  --> $DIR/generics-mismatch.rs:13:18
+   |
+LL | trait Foo {
+   |       ---
+LL |     async fn foo<T>();
+   |                  - expected type parameter
+...
+LL | impl Foo for () {
+   | ---------------
+LL |     async fn foo<const N: usize>() {}
+   |                  ^^^^^^^^^^^^^^ found const parameter of type `usize`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/async-await/in-trait/generics-mismatch.next.stderr b/tests/ui/async-await/in-trait/generics-mismatch.next.stderr
new file mode 100644
index 00000000000..be23384e049
--- /dev/null
+++ b/tests/ui/async-await/in-trait/generics-mismatch.next.stderr
@@ -0,0 +1,16 @@
+error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo`
+  --> $DIR/generics-mismatch.rs:13:18
+   |
+LL | trait Foo {
+   |       ---
+LL |     async fn foo<T>();
+   |                  - expected type parameter
+...
+LL | impl Foo for () {
+   | ---------------
+LL |     async fn foo<const N: usize>() {}
+   |                  ^^^^^^^^^^^^^^ found const parameter of type `usize`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/async-await/in-trait/generics-mismatch.rs b/tests/ui/async-await/in-trait/generics-mismatch.rs
new file mode 100644
index 00000000000..fc29783c0e3
--- /dev/null
+++ b/tests/ui/async-await/in-trait/generics-mismatch.rs
@@ -0,0 +1,15 @@
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    async fn foo<T>();
+}
+
+impl Foo for () {
+    async fn foo<const N: usize>() {}
+    //~^ ERROR: method `foo` has an incompatible generic parameter for trait `Foo` [E0053]
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/in-trait/generics-mismatch.stderr b/tests/ui/async-await/in-trait/generics-mismatch.stderr
new file mode 100644
index 00000000000..3518aa05cec
--- /dev/null
+++ b/tests/ui/async-await/in-trait/generics-mismatch.stderr
@@ -0,0 +1,16 @@
+error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo`
+  --> $DIR/generics-mismatch.rs:11:18
+   |
+LL | trait Foo {
+   |       ---
+LL |     async fn foo<T>();
+   |                  - expected type parameter
+...
+LL | impl Foo for () {
+   | ---------------
+LL |     async fn foo<const N: usize>() {}
+   |                  ^^^^^^^^^^^^^^ found const parameter of type `usize`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/async-await/in-trait/implied-bounds.rs b/tests/ui/async-await/in-trait/implied-bounds.rs
index 52bceb3cc5c..45ada1d84c3 100644
--- a/tests/ui/async-await/in-trait/implied-bounds.rs
+++ b/tests/ui/async-await/in-trait/implied-bounds.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/async-await/in-trait/issue-102138.rs b/tests/ui/async-await/in-trait/issue-102138.rs
index f61b34ed99e..ced30b7e4e4 100644
--- a/tests/ui/async-await/in-trait/issue-102138.rs
+++ b/tests/ui/async-await/in-trait/issue-102138.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/async-await/in-trait/issue-102219.rs b/tests/ui/async-await/in-trait/issue-102219.rs
index 9a35f6515cb..f3fdfa3459a 100644
--- a/tests/ui/async-await/in-trait/issue-102219.rs
+++ b/tests/ui/async-await/in-trait/issue-102219.rs
@@ -1,6 +1,8 @@
 // compile-flags:--crate-type=lib
 // edition:2021
 // check-pass
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/async-await/in-trait/issue-102310.rs b/tests/ui/async-await/in-trait/issue-102310.rs
index 49c3e9feeb4..8e5dbd08eb9 100644
--- a/tests/ui/async-await/in-trait/issue-102310.rs
+++ b/tests/ui/async-await/in-trait/issue-102310.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/async-await/in-trait/lifetime-mismatch.stderr b/tests/ui/async-await/in-trait/lifetime-mismatch.current.stderr
index d87adcc78b6..0e9477544a4 100644
--- a/tests/ui/async-await/in-trait/lifetime-mismatch.stderr
+++ b/tests/ui/async-await/in-trait/lifetime-mismatch.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/lifetime-mismatch.rs:3:12
+  --> $DIR/lifetime-mismatch.rs:5:12
    |
 LL | #![feature(async_fn_in_trait)]
    |            ^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | #![feature(async_fn_in_trait)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
-  --> $DIR/lifetime-mismatch.rs:12:17
+  --> $DIR/lifetime-mismatch.rs:14:17
    |
 LL |     async fn foo<'a>(&self);
    |                 ---- lifetimes in impl do not match this method in trait
diff --git a/tests/ui/async-await/in-trait/lifetime-mismatch.next.stderr b/tests/ui/async-await/in-trait/lifetime-mismatch.next.stderr
new file mode 100644
index 00000000000..0e9477544a4
--- /dev/null
+++ b/tests/ui/async-await/in-trait/lifetime-mismatch.next.stderr
@@ -0,0 +1,21 @@
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/lifetime-mismatch.rs:5:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
+  --> $DIR/lifetime-mismatch.rs:14:17
+   |
+LL |     async fn foo<'a>(&self);
+   |                 ---- lifetimes in impl do not match this method in trait
+...
+LL |     async fn foo(&self) {}
+   |                 ^ lifetimes do not match method in trait
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0195`.
diff --git a/tests/ui/async-await/in-trait/lifetime-mismatch.rs b/tests/ui/async-await/in-trait/lifetime-mismatch.rs
index 45ede193c0f..5ff5a01a1ee 100644
--- a/tests/ui/async-await/in-trait/lifetime-mismatch.rs
+++ b/tests/ui/async-await/in-trait/lifetime-mismatch.rs
@@ -1,4 +1,6 @@
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.current.stderr
index 5cedf3ddb0f..319ed582e27 100644
--- a/tests/ui/async-await/in-trait/missing-send-bound.stderr
+++ b/tests/ui/async-await/in-trait/missing-send-bound.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/missing-send-bound.rs:3:12
+  --> $DIR/missing-send-bound.rs:5:12
    |
 LL | #![feature(async_fn_in_trait)]
    |            ^^^^^^^^^^^^^^^^^
@@ -8,19 +8,19 @@ LL | #![feature(async_fn_in_trait)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error: future cannot be sent between threads safely
-  --> $DIR/missing-send-bound.rs:15:20
+  --> $DIR/missing-send-bound.rs:17:20
    |
 LL |     assert_is_send(test::<T>());
    |                    ^^^^^^^^^^^ future returned by `test` is not `Send`
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`
 note: future is not `Send` as it awaits another future which is not `Send`
-  --> $DIR/missing-send-bound.rs:11:5
+  --> $DIR/missing-send-bound.rs:13:5
    |
 LL |     T::bar().await;
    |     ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send`
 note: required by a bound in `assert_is_send`
-  --> $DIR/missing-send-bound.rs:19:27
+  --> $DIR/missing-send-bound.rs:21:27
    |
 LL | fn assert_is_send(_: impl Send) {}
    |                           ^^^^ required by this bound in `assert_is_send`
diff --git a/tests/ui/async-await/in-trait/missing-send-bound.next.stderr b/tests/ui/async-await/in-trait/missing-send-bound.next.stderr
new file mode 100644
index 00000000000..319ed582e27
--- /dev/null
+++ b/tests/ui/async-await/in-trait/missing-send-bound.next.stderr
@@ -0,0 +1,29 @@
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/missing-send-bound.rs:5:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: future cannot be sent between threads safely
+  --> $DIR/missing-send-bound.rs:17:20
+   |
+LL |     assert_is_send(test::<T>());
+   |                    ^^^^^^^^^^^ future returned by `test` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`
+note: future is not `Send` as it awaits another future which is not `Send`
+  --> $DIR/missing-send-bound.rs:13:5
+   |
+LL |     T::bar().await;
+   |     ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send`
+note: required by a bound in `assert_is_send`
+  --> $DIR/missing-send-bound.rs:21:27
+   |
+LL | fn assert_is_send(_: impl Send) {}
+   |                           ^^^^ required by this bound in `assert_is_send`
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/ui/async-await/in-trait/missing-send-bound.rs b/tests/ui/async-await/in-trait/missing-send-bound.rs
index 78922b59b27..705fcf322f9 100644
--- a/tests/ui/async-await/in-trait/missing-send-bound.rs
+++ b/tests/ui/async-await/in-trait/missing-send-bound.rs
@@ -1,4 +1,6 @@
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
diff --git a/tests/ui/async-await/in-trait/object-safety.stderr b/tests/ui/async-await/in-trait/object-safety.current.stderr
index 0b318f71f39..90e049a9960 100644
--- a/tests/ui/async-await/in-trait/object-safety.stderr
+++ b/tests/ui/async-await/in-trait/object-safety.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/object-safety.rs:3:12
+  --> $DIR/object-safety.rs:5:12
    |
 LL | #![feature(async_fn_in_trait)]
    |            ^^^^^^^^^^^^^^^^^
@@ -8,13 +8,13 @@ LL | #![feature(async_fn_in_trait)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety.rs:11:12
+  --> $DIR/object-safety.rs:13:12
    |
 LL |     let x: &dyn Foo = todo!();
    |            ^^^^^^^^ `Foo` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/object-safety.rs:7:14
+  --> $DIR/object-safety.rs:9:14
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
diff --git a/tests/ui/async-await/in-trait/object-safety.next.stderr b/tests/ui/async-await/in-trait/object-safety.next.stderr
new file mode 100644
index 00000000000..90e049a9960
--- /dev/null
+++ b/tests/ui/async-await/in-trait/object-safety.next.stderr
@@ -0,0 +1,27 @@
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/object-safety.rs:5:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/object-safety.rs:13:12
+   |
+LL |     let x: &dyn Foo = todo!();
+   |            ^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety.rs:9:14
+   |
+LL | trait Foo {
+   |       --- this trait cannot be made into an object...
+LL |     async fn foo(&self);
+   |              ^^^ ...because method `foo` is `async`
+   = help: consider moving `foo` to another trait
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/async-await/in-trait/object-safety.rs b/tests/ui/async-await/in-trait/object-safety.rs
index a8bc35f7e0c..f67286a20a2 100644
--- a/tests/ui/async-await/in-trait/object-safety.rs
+++ b/tests/ui/async-await/in-trait/object-safety.rs
@@ -1,4 +1,6 @@
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.stderr b/tests/ui/async-await/in-trait/return-type-suggestion.current.stderr
index b8d83d0f28a..a5efc757156 100644
--- a/tests/ui/async-await/in-trait/return-type-suggestion.stderr
+++ b/tests/ui/async-await/in-trait/return-type-suggestion.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/return-type-suggestion.rs:3:12
+  --> $DIR/return-type-suggestion.rs:5:12
    |
 LL | #![feature(async_fn_in_trait)]
    |            ^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | #![feature(async_fn_in_trait)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0308]: mismatched types
-  --> $DIR/return-type-suggestion.rs:8:9
+  --> $DIR/return-type-suggestion.rs:10:9
    |
 LL |         Ok(())
    |         ^^^^^^- help: consider using a semicolon here: `;`
diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.next.stderr b/tests/ui/async-await/in-trait/return-type-suggestion.next.stderr
new file mode 100644
index 00000000000..a5efc757156
--- /dev/null
+++ b/tests/ui/async-await/in-trait/return-type-suggestion.next.stderr
@@ -0,0 +1,23 @@
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/return-type-suggestion.rs:5:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+  --> $DIR/return-type-suggestion.rs:10:9
+   |
+LL |         Ok(())
+   |         ^^^^^^- help: consider using a semicolon here: `;`
+   |         |
+   |         expected `()`, found `Result<(), _>`
+   |
+   = note: expected unit type `()`
+                   found enum `Result<(), _>`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.rs b/tests/ui/async-await/in-trait/return-type-suggestion.rs
index 3446761d119..3de66306d9a 100644
--- a/tests/ui/async-await/in-trait/return-type-suggestion.rs
+++ b/tests/ui/async-await/in-trait/return-type-suggestion.rs
@@ -1,4 +1,6 @@
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
diff --git a/tests/ui/async-await/large_moves.attribute.stderr b/tests/ui/async-await/large_moves.attribute.stderr
index 0c5452475a6..94f61caa25d 100644
--- a/tests/ui/async-await/large_moves.attribute.stderr
+++ b/tests/ui/async-await/large_moves.attribute.stderr
@@ -1,14 +1,8 @@
 error: moving 10024 bytes
-  --> $DIR/large_moves.rs:13:13
+  --> $DIR/large_moves.rs:19:14
    |
-LL |       let x = async {
-   |  _____________^
-LL | |         let y = [0; 9999];
-LL | |         dbg!(y);
-LL | |         thing(&y).await;
-LL | |         dbg!(y);
-LL | |     };
-   | |_____^ value moved from here
+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
@@ -18,14 +12,6 @@ LL | #![deny(large_assignments)]
    |         ^^^^^^^^^^^^^^^^^
 
 error: moving 10024 bytes
-  --> $DIR/large_moves.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 = "..."]`
-
-error: moving 10024 bytes
   --> $DIR/large_moves.rs:19:13
    |
 LL |     let z = (x, 42);
@@ -41,5 +27,5 @@ LL |     let a = z.0;
    |
    = 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
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/async-await/large_moves.option.stderr b/tests/ui/async-await/large_moves.option.stderr
index 0c5452475a6..94f61caa25d 100644
--- a/tests/ui/async-await/large_moves.option.stderr
+++ b/tests/ui/async-await/large_moves.option.stderr
@@ -1,14 +1,8 @@
 error: moving 10024 bytes
-  --> $DIR/large_moves.rs:13:13
+  --> $DIR/large_moves.rs:19:14
    |
-LL |       let x = async {
-   |  _____________^
-LL | |         let y = [0; 9999];
-LL | |         dbg!(y);
-LL | |         thing(&y).await;
-LL | |         dbg!(y);
-LL | |     };
-   | |_____^ value moved from here
+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
@@ -18,14 +12,6 @@ LL | #![deny(large_assignments)]
    |         ^^^^^^^^^^^^^^^^^
 
 error: moving 10024 bytes
-  --> $DIR/large_moves.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 = "..."]`
-
-error: moving 10024 bytes
   --> $DIR/large_moves.rs:19:13
    |
 LL |     let z = (x, 42);
@@ -41,5 +27,5 @@ LL |     let a = z.0;
    |
    = 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
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/async-await/large_moves.rs b/tests/ui/async-await/large_moves.rs
index d43d0eec0ca..c8ed6bafe9c 100644
--- a/tests/ui/async-await/large_moves.rs
+++ b/tests/ui/async-await/large_moves.rs
@@ -10,7 +10,7 @@
 // compile-flags: -Zmir-opt-level=0
 
 fn main() {
-    let x = async { //~ ERROR large_assignments
+    let x = async {
         let y = [0; 9999];
         dbg!(y);
         thing(&y).await;
diff --git a/tests/ui/async-await/no-const-async.rs b/tests/ui/async-await/no-const-async.rs
index cfb0ef1b33a..b3c59734e03 100644
--- a/tests/ui/async-await/no-const-async.rs
+++ b/tests/ui/async-await/no-const-async.rs
@@ -3,4 +3,3 @@
 
 pub const async fn x() {}
 //~^ ERROR functions cannot be both `const` and `async`
-//~| ERROR cycle detected
diff --git a/tests/ui/async-await/no-const-async.stderr b/tests/ui/async-await/no-const-async.stderr
index 71c228958f6..90ec646c8c0 100644
--- a/tests/ui/async-await/no-const-async.stderr
+++ b/tests/ui/async-await/no-const-async.stderr
@@ -7,36 +7,5 @@ LL | pub const async fn x() {}
    |     |     `async` because of this
    |     `const` because of this
 
-error[E0391]: cycle detected when computing type of `x::{opaque#0}`
-  --> $DIR/no-const-async.rs:4:24
-   |
-LL | pub const async fn x() {}
-   |                        ^
-   |
-note: ...which requires borrow-checking `x`...
-  --> $DIR/no-const-async.rs:4:1
-   |
-LL | pub const async fn x() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing MIR for `x`...
-  --> $DIR/no-const-async.rs:4:1
-   |
-LL | pub const async fn x() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const checking `x`...
-  --> $DIR/no-const-async.rs:4:1
-   |
-LL | pub const async fn x() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing whether `x::{opaque#0}` is freeze...
-   = note: ...which requires evaluating trait selection obligation `x::{opaque#0}: core::marker::Freeze`...
-   = note: ...which again requires computing type of `x::{opaque#0}`, completing the cycle
-note: cycle used when checking item types in top-level module
-  --> $DIR/no-const-async.rs:4:1
-   |
-LL | pub const async fn x() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/async-await/track-caller/async-block.rs b/tests/ui/async-await/track-caller/async-block.rs
index 8e81387c34b..8ddd4ab1186 100644
--- a/tests/ui/async-await/track-caller/async-block.rs
+++ b/tests/ui/async-await/track-caller/async-block.rs
@@ -1,9 +1,9 @@
 // edition:2021
 
-#![feature(closure_track_caller, stmt_expr_attributes)]
+#![feature(stmt_expr_attributes)]
 
 fn main() {
     let _ = #[track_caller] async {
-        //~^ ERROR attribute should be applied to a function definition [E0739]
+        //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658]
     };
 }
diff --git a/tests/ui/async-await/track-caller/async-block.stderr b/tests/ui/async-await/track-caller/async-block.stderr
index 407439921c0..21d1054d220 100644
--- a/tests/ui/async-await/track-caller/async-block.stderr
+++ b/tests/ui/async-await/track-caller/async-block.stderr
@@ -1,12 +1,12 @@
-error[E0739]: attribute should be applied to a function definition
+error[E0658]: `#[track_caller]` on closures is currently unstable
   --> $DIR/async-block.rs:6:13
    |
-LL |       let _ = #[track_caller] async {
-   |  _____________^^^^^^^^^^^^^^^_-
-LL | |
-LL | |     };
-   | |_____- not a function definition
+LL |     let _ = #[track_caller] async {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0739`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/async-await/track-caller/panic-track-caller.rs b/tests/ui/async-await/track-caller/panic-track-caller.rs
index f45243b0ea6..65bb23e0b4b 100644
--- a/tests/ui/async-await/track-caller/panic-track-caller.rs
+++ b/tests/ui/async-await/track-caller/panic-track-caller.rs
@@ -79,6 +79,16 @@ async fn foo_closure() {
     c().await
 }
 
+// Since compilation is expected to fail for this fn when using
+// `nofeat`, we test that separately in `async-block.rs`
+#[cfg(feat)]
+async fn foo_block() {
+    let a = #[track_caller] async {
+        panic!();
+    };
+    a.await
+}
+
 fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 {
     let loc = Arc::new(Mutex::new(None));
 
@@ -110,4 +120,7 @@ fn main() {
 
     #[cfg(feat)]
     assert_eq!(panicked_at(|| block_on(foo_closure())), 79);
+
+    #[cfg(feat)]
+    assert_eq!(panicked_at(|| block_on(foo_block())), 89);
 }
diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr
index 245c3a40e05..f032ea779dd 100644
--- a/tests/ui/borrowck/issue-64453.stderr
+++ b/tests/ui/borrowck/issue-64453.stderr
@@ -1,4 +1,4 @@
-error: `Arguments::<'a>::new_v1` is not yet stable as a const fn
+error: `Arguments::<'a>::new_const` is not yet stable as a const fn
   --> $DIR/issue-64453.rs:4:31
    |
 LL | static settings_dir: String = format!("");
diff --git a/tests/ui/chalkify/bugs/async.rs b/tests/ui/chalkify/bugs/async.rs
index 3169e4781ee..a1ef4732b63 100644
--- a/tests/ui/chalkify/bugs/async.rs
+++ b/tests/ui/chalkify/bugs/async.rs
@@ -4,7 +4,7 @@
 // compile-flags:-Z trait-solver=chalk
 // error-pattern:internal compiler error
 // failure-status:101
-// normalize-stderr-test "DefId([^)]*)" -> "..."
+// normalize-stderr-test "DefId\([^)]*\)" -> "..."
 // normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
 // normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
diff --git a/tests/ui/chalkify/bugs/async.stderr b/tests/ui/chalkify/bugs/async.stderr
index 8043f1e5a05..9c559640b23 100644
--- a/tests/ui/chalkify/bugs/async.stderr
+++ b/tests/ui/chalkify/bugs/async.stderr
@@ -1,34 +1,4 @@
 error[E0277]: `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
-  --> $DIR/async.rs:23:29
-   |
-LL |   async fn foo(x: u32) -> u32 {
-   |  _____________________________-
-LL | |     x
-LL | | }
-   | | ^
-   | | |
-   | |_`[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
-   |   required by a bound introduced by this call
-   |
-   = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]`
-   = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited
-note: required by a bound in `identity_future`
-  --> $SRC_DIR/core/src/future/mod.rs:LL:COL
-
-error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:23:29: 25:2] as Future>::Output` cannot be known at compilation time
-  --> $DIR/async.rs:23:29
-   |
-LL |   async fn foo(x: u32) -> u32 {
-   |  _____________________________^
-LL | |     x
-LL | | }
-   | |_^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `<[async fn body@$DIR/async.rs:23:29: 25:2] as Future>::Output`
-note: required by a bound in `identity_future`
-  --> $SRC_DIR/core/src/future/mod.rs:LL:COL
-
-error[E0277]: `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
   --> $DIR/async.rs:23:25
    |
 LL | async fn foo(x: u32) -> u32 {
@@ -37,7 +7,7 @@ LL | async fn foo(x: u32) -> u32 {
    = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]`
    = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited
 
-error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ...) }, Term::Ty(u32)), []), depth=0)`
+error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ... }, Term::Ty(u32)), []), depth=0)`
   --> $DIR/async.rs:23:25
    |
 LL | async fn foo(x: u32) -> u32 {
@@ -53,6 +23,6 @@ LL | async fn foo(x: u32) -> u32 {
 #8 [check_mod_item_types] checking item types in top-level module
 #9 [analysis] running analysis passes on this crate
 end of query stack
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/codegen/mono-impossible.rs b/tests/ui/codegen/mono-impossible.rs
new file mode 100644
index 00000000000..1ea32ed2c4f
--- /dev/null
+++ b/tests/ui/codegen/mono-impossible.rs
@@ -0,0 +1,13 @@
+// compile-flags: -Clink-dead-code=on --crate-type=lib
+// build-pass
+
+// Make sure that we don't monomorphize the impossible method `<() as Visit>::visit`,
+// which does not hold under a reveal-all param env.
+
+pub trait Visit {
+    fn visit() {}
+}
+
+pub trait Array<'a> {}
+
+impl Visit for () where (): for<'a> Array<'a> {}
diff --git a/tests/ui/conditional-compilation/cfg-attr-multi-true.stderr b/tests/ui/conditional-compilation/cfg-attr-multi-true.stderr
index fbfcd45652f..123ce71727f 100644
--- a/tests/ui/conditional-compilation/cfg-attr-multi-true.stderr
+++ b/tests/ui/conditional-compilation/cfg-attr-multi-true.stderr
@@ -35,6 +35,10 @@ note: the lint level is defined here
    |
 LL | #![warn(unused_must_use)]
    |         ^^^^^^^^^^^^^^^
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = MustUseDeprecated::new();
+   |     +++++++
 
 warning: 5 warnings emitted
 
diff --git a/tests/ui/const-generics/bad-subst-const-kind.rs b/tests/ui/const-generics/bad-subst-const-kind.rs
new file mode 100644
index 00000000000..e13dfbacd24
--- /dev/null
+++ b/tests/ui/const-generics/bad-subst-const-kind.rs
@@ -0,0 +1,13 @@
+// incremental
+#![crate_type = "lib"]
+
+trait Q {
+    const ASSOC: usize;
+}
+
+impl<const N: u64> Q for [u8; N] {
+    //~^ ERROR mismatched types
+    const ASSOC: usize = 1;
+}
+
+pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
diff --git a/tests/ui/const-generics/bad-subst-const-kind.stderr b/tests/ui/const-generics/bad-subst-const-kind.stderr
new file mode 100644
index 00000000000..bd24f9140e4
--- /dev/null
+++ b/tests/ui/const-generics/bad-subst-const-kind.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/bad-subst-const-kind.rs:8:31
+   |
+LL | impl<const N: u64> Q for [u8; N] {
+   |                               ^ expected `usize`, found `u64`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/const-arg-in-const-arg.full.stderr b/tests/ui/const-generics/const-arg-in-const-arg.full.stderr
index 8672e79b3e8..463a37d7e3d 100644
--- a/tests/ui/const-generics/const-arg-in-const-arg.full.stderr
+++ b/tests/ui/const-generics/const-arg-in-const-arg.full.stderr
@@ -1,4 +1,4 @@
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:18:23
    |
 LL |     let _: [u8; faz::<'a>(&())];
@@ -10,7 +10,7 @@ note: the late bound lifetime parameter is introduced here
 LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:21:23
    |
 LL |     let _: [u8; faz::<'b>(&())];
@@ -22,7 +22,7 @@ note: the late bound lifetime parameter is introduced here
 LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:41:24
    |
 LL |     let _: Foo<{ faz::<'a>(&()) }>;
@@ -34,7 +34,7 @@ note: the late bound lifetime parameter is introduced here
 LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:44:24
    |
 LL |     let _: Foo<{ faz::<'b>(&()) }>;
@@ -94,7 +94,7 @@ LL |     let _ = [0; bar::<N>()];
    |
    = help: try adding a `where` bound using this expression: `where [(); bar::<N>()]:`
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:30:23
    |
 LL |     let _ = [0; faz::<'a>(&())];
@@ -106,7 +106,7 @@ note: the late bound lifetime parameter is introduced here
 LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:33:23
    |
 LL |     let _ = [0; faz::<'b>(&())];
@@ -134,7 +134,7 @@ LL |     let _ = Foo::<{ bar::<N>() }>;
    |
    = help: try adding a `where` bound using this expression: `where [(); { bar::<N>() }]:`
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:52:27
    |
 LL |     let _ = Foo::<{ faz::<'a>(&()) }>;
@@ -146,7 +146,7 @@ note: the late bound lifetime parameter is introduced here
 LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:55:27
    |
 LL |     let _ = Foo::<{ faz::<'b>(&()) }>;
@@ -160,3 +160,4 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
 
 error: aborting due to 16 previous errors
 
+For more information about this error, try `rustc --explain E0794`.
diff --git a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr
index f1353aa9943..a7bd9c62b0e 100644
--- a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr
+++ b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr
@@ -216,7 +216,7 @@ help: if this generic argument was intended as a const parameter, surround it wi
 LL |     let _: [u8; bar::<{ N }>()];
    |                       +   +
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:18:23
    |
 LL |     let _: [u8; faz::<'a>(&())];
@@ -228,7 +228,7 @@ note: the late bound lifetime parameter is introduced here
 LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:21:23
    |
 LL |     let _: [u8; faz::<'b>(&())];
@@ -251,7 +251,7 @@ help: if this generic argument was intended as a const parameter, surround it wi
 LL |     let _: Foo<{ bar::<{ N }>() }>;
    |                        +   +
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:41:24
    |
 LL |     let _: Foo<{ faz::<'a>(&()) }>;
@@ -263,7 +263,7 @@ note: the late bound lifetime parameter is introduced here
 LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:44:24
    |
 LL |     let _: Foo<{ faz::<'b>(&()) }>;
@@ -294,7 +294,7 @@ help: if this generic argument was intended as a const parameter, surround it wi
 LL |     let _ = [0; bar::<{ N }>()];
    |                       +   +
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:30:23
    |
 LL |     let _ = [0; faz::<'a>(&())];
@@ -306,7 +306,7 @@ note: the late bound lifetime parameter is introduced here
 LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:33:23
    |
 LL |     let _ = [0; faz::<'b>(&())];
@@ -329,7 +329,7 @@ help: if this generic argument was intended as a const parameter, surround it wi
 LL |     let _ = Foo::<{ bar::<{ N }>() }>;
    |                           +   +
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:52:27
    |
 LL |     let _ = Foo::<{ faz::<'a>(&()) }>;
@@ -341,7 +341,7 @@ note: the late bound lifetime parameter is introduced here
 LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:55:27
    |
 LL |     let _ = Foo::<{ faz::<'b>(&()) }>;
@@ -355,5 +355,5 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
 
 error: aborting due to 36 previous errors
 
-Some errors have detailed explanations: E0658, E0747.
+Some errors have detailed explanations: E0658, E0747, E0794.
 For more information about an error, try `rustc --explain E0658`.
diff --git a/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.rs b/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.rs
new file mode 100644
index 00000000000..734a3786294
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.rs
@@ -0,0 +1,11 @@
+#![feature(generic_const_exprs)]
+//~^ WARN the feature `generic_const_exprs` is incomplete
+
+trait B {
+    type U<T>;
+}
+
+fn f<T: B<U<1i32> = ()>>() {}
+//~^ ERROR constant provided when a type was expected
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.stderr b/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.stderr
new file mode 100644
index 00000000000..8b6eb5b7594
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.stderr
@@ -0,0 +1,18 @@
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/mismatched-gat-subst-kind.rs:1:12
+   |
+LL | #![feature(generic_const_exprs)]
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0747]: constant provided when a type was expected
+  --> $DIR/mismatched-gat-subst-kind.rs:8:13
+   |
+LL | fn f<T: B<U<1i32> = ()>>() {}
+   |             ^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/tests/ui/const-ptr/out_of_bounds_read.stderr b/tests/ui/const-ptr/out_of_bounds_read.stderr
index 3e7b09a5982..89536f53f08 100644
--- a/tests/ui/const-ptr/out_of_bounds_read.stderr
+++ b/tests/ui/const-ptr/out_of_bounds_read.stderr
@@ -1,7 +1,7 @@
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-   = note: memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
+   = note: dereferencing pointer failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
    |
 note: inside `std::ptr::read::<u32>`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
@@ -14,7 +14,7 @@ LL |     const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-   = note: memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
+   = note: dereferencing pointer failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
    |
 note: inside `std::ptr::read::<u32>`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
@@ -29,7 +29,7 @@ LL |     const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-   = note: memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
+   = note: dereferencing pointer failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
    |
 note: inside `std::ptr::read::<u32>`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
diff --git a/tests/ui/consts/const-eval/format.rs b/tests/ui/consts/const-eval/format.rs
index 0d8b7c12d8a..5bdb2bf1954 100644
--- a/tests/ui/consts/const-eval/format.rs
+++ b/tests/ui/consts/const-eval/format.rs
@@ -1,12 +1,13 @@
 const fn failure() {
     panic!("{:?}", 0);
     //~^ ERROR cannot call non-const formatting macro in constant functions
+    //~| ERROR cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions
 }
 
 const fn print() {
     println!("{:?}", 0);
     //~^ ERROR cannot call non-const formatting macro in constant functions
-    //~| ERROR `Arguments::<'a>::new_v1` is not yet stable as a const fn
+    //~| ERROR cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions
     //~| ERROR cannot call non-const fn `_print` in constant functions
 }
 
diff --git a/tests/ui/consts/const-eval/format.stderr b/tests/ui/consts/const-eval/format.stderr
index 4bf39db5874..c39920d444d 100644
--- a/tests/ui/consts/const-eval/format.stderr
+++ b/tests/ui/consts/const-eval/format.stderr
@@ -7,8 +7,17 @@ LL |     panic!("{:?}", 0);
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
+error[E0015]: cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions
+  --> $DIR/format.rs:2:5
+   |
+LL |     panic!("{:?}", 0);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error[E0015]: cannot call non-const formatting macro in constant functions
-  --> $DIR/format.rs:7:22
+  --> $DIR/format.rs:8:22
    |
 LL |     println!("{:?}", 0);
    |                      ^
@@ -16,17 +25,17 @@ LL |     println!("{:?}", 0);
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: `Arguments::<'a>::new_v1` is not yet stable as a const fn
-  --> $DIR/format.rs:7:5
+error[E0015]: cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions
+  --> $DIR/format.rs:8:5
    |
 LL |     println!("{:?}", 0);
    |     ^^^^^^^^^^^^^^^^^^^
    |
-   = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `_print` in constant functions
-  --> $DIR/format.rs:7:5
+  --> $DIR/format.rs:8:5
    |
 LL |     println!("{:?}", 0);
    |     ^^^^^^^^^^^^^^^^^^^
@@ -63,19 +72,19 @@ LL |     panic!("{:?}", 0);
    = note: this note originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant used
-  --> $DIR/format.rs:7:14
+  --> $DIR/format.rs:8:14
    |
 LL |     println!("{:?}", 0);
    |              ^^^^^^
 
 note: erroneous constant used
-  --> $DIR/format.rs:7:14
+  --> $DIR/format.rs:8:14
    |
 LL |     println!("{:?}", 0);
    |              ^^^^^^
 
 note: erroneous constant used
-  --> $DIR/format.rs:7:22
+  --> $DIR/format.rs:8:22
    |
 LL |     println!("{:?}", 0);
    |                      ^
@@ -83,13 +92,13 @@ LL |     println!("{:?}", 0);
    = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant used
-  --> $DIR/format.rs:7:22
+  --> $DIR/format.rs:8:22
    |
 LL |     println!("{:?}", 0);
    |                      ^
    |
    = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
index 6bd367b6469..080568b51ef 100644
--- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
@@ -148,11 +148,11 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
                HEX_DUMP
            }
 
-error: accessing memory with alignment 1, but alignment 4 is required
+error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+   = note: accessing memory with alignment 1, but alignment 4 is required
+   |
 note: inside `std::ptr::read::<u32>`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
 note: inside `ptr::const_ptr::<impl *const u32>::read`
@@ -162,25 +162,7 @@ note: inside `UNALIGNED_READ`
    |
 LL |     ptr.read();
    |     ^^^^^^^^^^
-   = note: `#[deny(invalid_alignment)]` on by default
 
 error: aborting due to 15 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
-Future incompatibility report: Future breakage diagnostic:
-error: accessing memory with alignment 1, but alignment 4 is required
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
-note: inside `std::ptr::read::<u32>`
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `UNALIGNED_READ`
-  --> $DIR/ub-ref-ptr.rs:67:5
-   |
-LL |     ptr.read();
-   |     ^^^^^^^^^^
-   = note: `#[deny(invalid_alignment)]` on by default
-
diff --git a/tests/ui/consts/issue-miri-1910.stderr b/tests/ui/consts/issue-miri-1910.stderr
index 61865b1dad7..a10eea9de11 100644
--- a/tests/ui/consts/issue-miri-1910.stderr
+++ b/tests/ui/consts/issue-miri-1910.stderr
@@ -1,7 +1,7 @@
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-   = note: unable to copy parts of a pointer from memory at ALLOC
+   = note: unable to turn pointer into raw bytes
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr
index fff4729689f..6530084a585 100644
--- a/tests/ui/consts/offset_from_ub.stderr
+++ b/tests/ui/consts/offset_from_ub.stderr
@@ -39,19 +39,19 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:53:14
    |
 LL |     unsafe { ptr_offset_from(end_ptr, start_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc18 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc17 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:62:14
    |
 LL |     unsafe { ptr_offset_from(start_ptr, end_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc21 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc20 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:70:14
    |
 LL |     unsafe { ptr_offset_from(end_ptr, end_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc24 has size 4, so pointer at offset 10 is out-of-bounds
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc23 has size 4, so pointer at offset 10 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:79:14
diff --git a/tests/ui/did_you_mean/recursion_limit.stderr b/tests/ui/did_you_mean/recursion_limit.stderr
index 247fe4b5b07..70e49566ac0 100644
--- a/tests/ui/did_you_mean/recursion_limit.stderr
+++ b/tests/ui/did_you_mean/recursion_limit.stderr
@@ -1,15 +1,10 @@
-error[E0275]: overflow evaluating the requirement `K: Send`
+error[E0275]: overflow evaluating the requirement `J: Send`
   --> $DIR/recursion_limit.rs:34:5
    |
 LL |     is_send::<A>();
    |     ^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit`)
-note: required because it appears within the type `J`
-  --> $DIR/recursion_limit.rs:24:9
-   |
-LL | link! { J, K }
-   |         ^
 note: required because it appears within the type `I`
   --> $DIR/recursion_limit.rs:23:9
    |
diff --git a/tests/ui/error-codes/E0275.stderr b/tests/ui/error-codes/E0275.stderr
index cf9a7f69bfb..03c37d6f0e1 100644
--- a/tests/ui/error-codes/E0275.stderr
+++ b/tests/ui/error-codes/E0275.stderr
@@ -11,7 +11,7 @@ note: required for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<
 LL | impl<T> Foo for T where Bar<T>: Foo {}
    |         ^^^     ^               --- unsatisfied trait bound introduced here
    = note: the full type name has been written to '$TEST_BUILD_DIR/error-codes/E0275/E0275.long-type-hash.txt'
-   = note: 127 redundant requirements hidden
+   = note: 126 redundant requirements hidden
    = note: required for `Bar<T>` to implement `Foo`
 
 error: aborting due to previous error
diff --git a/tests/ui/feature-gates/feature-gate-closure_track_caller.rs b/tests/ui/feature-gates/feature-gate-closure_track_caller.rs
index a8d63a8145a..a4c91f3bc18 100644
--- a/tests/ui/feature-gates/feature-gate-closure_track_caller.rs
+++ b/tests/ui/feature-gates/feature-gate-closure_track_caller.rs
@@ -1,7 +1,9 @@
+// edition:2021
 #![feature(stmt_expr_attributes)]
 #![feature(generators)]
 
 fn main() {
     let _closure = #[track_caller] || {}; //~ `#[track_caller]` on closures
     let _generator = #[track_caller] || { yield; }; //~ `#[track_caller]` on closures
+    let _future = #[track_caller] async {}; //~ `#[track_caller]` on closures
 }
diff --git a/tests/ui/feature-gates/feature-gate-closure_track_caller.stderr b/tests/ui/feature-gates/feature-gate-closure_track_caller.stderr
index ed63d74fe4d..cf2ea5fe1ca 100644
--- a/tests/ui/feature-gates/feature-gate-closure_track_caller.stderr
+++ b/tests/ui/feature-gates/feature-gate-closure_track_caller.stderr
@@ -1,5 +1,5 @@
 error[E0658]: `#[track_caller]` on closures is currently unstable
-  --> $DIR/feature-gate-closure_track_caller.rs:5:20
+  --> $DIR/feature-gate-closure_track_caller.rs:6:20
    |
 LL |     let _closure = #[track_caller] || {};
    |                    ^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     let _closure = #[track_caller] || {};
    = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
 
 error[E0658]: `#[track_caller]` on closures is currently unstable
-  --> $DIR/feature-gate-closure_track_caller.rs:6:22
+  --> $DIR/feature-gate-closure_track_caller.rs:7:22
    |
 LL |     let _generator = #[track_caller] || { yield; };
    |                      ^^^^^^^^^^^^^^^
@@ -16,6 +16,15 @@ LL |     let _generator = #[track_caller] || { yield; };
    = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
    = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
 
-error: aborting due to 2 previous errors
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/feature-gate-closure_track_caller.rs:8:19
+   |
+LL |     let _future = #[track_caller] async {};
+   |                   ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/fmt/auxiliary/format-string-proc-macro.rs b/tests/ui/fmt/auxiliary/format-string-proc-macro.rs
index 1b7ef93f41d..0c39ade721f 100644
--- a/tests/ui/fmt/auxiliary/format-string-proc-macro.rs
+++ b/tests/ui/fmt/auxiliary/format-string-proc-macro.rs
@@ -28,25 +28,41 @@ pub fn err_with_input_span(input: TokenStream) -> TokenStream {
     TokenStream::from(TokenTree::Literal(lit))
 }
 
+fn build_format(args: impl Into<TokenStream>) -> TokenStream {
+    TokenStream::from_iter([
+        TokenTree::from(Ident::new("format", Span::call_site())),
+        TokenTree::from(Punct::new('!', Spacing::Alone)),
+        TokenTree::from(Group::new(Delimiter::Parenthesis, args.into())),
+    ])
+}
 
 #[proc_macro]
 pub fn respan_to_invalid_format_literal(input: TokenStream) -> TokenStream {
     let mut s = Literal::string("{");
     s.set_span(input.into_iter().next().unwrap().span());
-    TokenStream::from_iter([
-        TokenTree::from(Ident::new("format", Span::call_site())),
-        TokenTree::from(Punct::new('!', Spacing::Alone)),
-        TokenTree::from(Group::new(Delimiter::Parenthesis, TokenTree::from(s).into())),
-    ])
+
+    build_format(TokenTree::from(s))
 }
 
 #[proc_macro]
 pub fn capture_a_with_prepended_space_preserve_span(input: TokenStream) -> TokenStream {
     let mut s = Literal::string(" {a}");
     s.set_span(input.into_iter().next().unwrap().span());
-    TokenStream::from_iter([
-        TokenTree::from(Ident::new("format", Span::call_site())),
-        TokenTree::from(Punct::new('!', Spacing::Alone)),
-        TokenTree::from(Group::new(Delimiter::Parenthesis, TokenTree::from(s).into())),
-    ])
+
+    build_format(TokenTree::from(s))
+}
+
+#[proc_macro]
+pub fn format_args_captures(_: TokenStream) -> TokenStream {
+    r#"{ let x = 5; format!("{x}") }"#.parse().unwrap()
+}
+
+#[proc_macro]
+pub fn bad_format_args_captures(_: TokenStream) -> TokenStream {
+    r#"{ let x = 5; format!(concat!("{x}")) }"#.parse().unwrap()
+}
+
+#[proc_macro]
+pub fn identity_pm(input: TokenStream) -> TokenStream {
+    input
 }
diff --git a/tests/ui/fmt/format-args-capture-first-literal-is-macro.rs b/tests/ui/fmt/format-args-capture-first-literal-is-macro.rs
new file mode 100644
index 00000000000..bf5c0dcb54d
--- /dev/null
+++ b/tests/ui/fmt/format-args-capture-first-literal-is-macro.rs
@@ -0,0 +1,21 @@
+// aux-build:format-string-proc-macro.rs
+
+#[macro_use]
+extern crate format_string_proc_macro;
+
+macro_rules! identity_mbe {
+    ($tt:tt) => {
+        $tt
+        //~^ ERROR there is no argument named `a`
+    };
+}
+
+fn main() {
+    let a = 0;
+
+    format!(identity_pm!("{a}"));
+    //~^ ERROR there is no argument named `a`
+    format!(identity_mbe!("{a}"));
+    format!(concat!("{a}"));
+    //~^ ERROR there is no argument named `a`
+}
diff --git a/tests/ui/fmt/format-args-capture-first-literal-is-macro.stderr b/tests/ui/fmt/format-args-capture-first-literal-is-macro.stderr
new file mode 100644
index 00000000000..4cf3afad7b8
--- /dev/null
+++ b/tests/ui/fmt/format-args-capture-first-literal-is-macro.stderr
@@ -0,0 +1,30 @@
+error: there is no argument named `a`
+  --> $DIR/format-args-capture-first-literal-is-macro.rs:16:26
+   |
+LL |     format!(identity_pm!("{a}"));
+   |                          ^^^^^
+   |
+   = note: did you intend to capture a variable `a` from the surrounding scope?
+   = note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
+
+error: there is no argument named `a`
+  --> $DIR/format-args-capture-first-literal-is-macro.rs:8:9
+   |
+LL |         $tt
+   |         ^^^
+   |
+   = note: did you intend to capture a variable `a` from the surrounding scope?
+   = note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
+
+error: there is no argument named `a`
+  --> $DIR/format-args-capture-first-literal-is-macro.rs:19:13
+   |
+LL |     format!(concat!("{a}"));
+   |             ^^^^^^^^^^^^^^
+   |
+   = note: did you intend to capture a variable `a` from the surrounding scope?
+   = note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
+   = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.rs b/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.rs
new file mode 100644
index 00000000000..f67edf5e167
--- /dev/null
+++ b/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.rs
@@ -0,0 +1,8 @@
+// aux-build:format-string-proc-macro.rs
+
+extern crate format_string_proc_macro;
+
+fn main() {
+    format_string_proc_macro::bad_format_args_captures!();
+    //~^ ERROR there is no argument named `x`
+}
diff --git a/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.stderr b/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.stderr
new file mode 100644
index 00000000000..bb6a14d88b3
--- /dev/null
+++ b/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.stderr
@@ -0,0 +1,12 @@
+error: there is no argument named `x`
+  --> $DIR/format-args-capture-from-pm-first-arg-macro.rs:6:5
+   |
+LL |     format_string_proc_macro::bad_format_args_captures!();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: did you intend to capture a variable `x` from the surrounding scope?
+   = note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
+   = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/fmt/format-args-capture-issue-106408.rs b/tests/ui/fmt/format-args-capture-issue-106408.rs
new file mode 100644
index 00000000000..0fd195416ee
--- /dev/null
+++ b/tests/ui/fmt/format-args-capture-issue-106408.rs
@@ -0,0 +1,10 @@
+// check-pass
+// aux-build:format-string-proc-macro.rs
+
+extern crate format_string_proc_macro;
+
+fn main() {
+    // While literal macros like `format_args!(concat!())` are not supposed to work with implicit
+    // captures, it should work if the whole invocation comes from a macro expansion (#106408).
+    format_string_proc_macro::format_args_captures!();
+}
diff --git a/tests/ui/fmt/format-args-capture-macro-hygiene-pass.rs b/tests/ui/fmt/format-args-capture-macro-hygiene-pass.rs
new file mode 100644
index 00000000000..7553fcc4e01
--- /dev/null
+++ b/tests/ui/fmt/format-args-capture-macro-hygiene-pass.rs
@@ -0,0 +1,16 @@
+// run-pass
+
+macro_rules! format_mbe {
+    ($tt:tt) => {
+        {
+            #[allow(unused_variables)]
+            let a = 123;
+            format!($tt)
+        }
+    };
+}
+
+fn main() {
+    let a = 0;
+    assert_eq!(format_mbe!("{a}"), "0");
+}
diff --git a/tests/ui/fmt/respanned-literal-issue-106191.rs b/tests/ui/fmt/respanned-literal-issue-106191.rs
index 5a18983a3fa..44642a10fc0 100644
--- a/tests/ui/fmt/respanned-literal-issue-106191.rs
+++ b/tests/ui/fmt/respanned-literal-issue-106191.rs
@@ -1,15 +1,10 @@
 // aux-build:format-string-proc-macro.rs
-// check-fail
-// known-bug: #106191
-// unset-rustc-env:RUST_BACKTRACE
-// had to be reverted
-// error-pattern:unexpectedly panicked
-// failure-status:101
-// dont-check-compiler-stderr
 
 extern crate format_string_proc_macro;
 
 fn main() {
     format_string_proc_macro::respan_to_invalid_format_literal!("¡");
+    //~^ ERROR invalid format string: expected `'}'` but string was terminated
     format_args!(r#concat!("¡        {"));
+    //~^ ERROR invalid format string: expected `'}'` but string was terminated
 }
diff --git a/tests/ui/fmt/respanned-literal-issue-106191.stderr b/tests/ui/fmt/respanned-literal-issue-106191.stderr
index 16717f42253..73a3af65a38 100644
--- a/tests/ui/fmt/respanned-literal-issue-106191.stderr
+++ b/tests/ui/fmt/respanned-literal-issue-106191.stderr
@@ -1,2 +1,19 @@
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  query stack during panic:
-end of query stack
+error: invalid format string: expected `'}'` but string was terminated
+  --> $DIR/respanned-literal-issue-106191.rs:6:65
+   |
+LL |     format_string_proc_macro::respan_to_invalid_format_literal!("¡");
+   |                                                                 ^^^ expected `'}'` in format string
+   |
+   = note: if you intended to print `{`, you can escape it using `{{`
+
+error: invalid format string: expected `'}'` but string was terminated
+  --> $DIR/respanned-literal-issue-106191.rs:8:18
+   |
+LL |     format_args!(r#concat!("¡        {"));
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^ expected `'}'` in format string
+   |
+   = note: if you intended to print `{`, you can escape it using `{{`
+   = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.current.stderr
index d681ecf25e8..05c025cc169 100644
--- a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr
+++ b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/box-coerce-span-in-default.rs:3:12
+  --> $DIR/box-coerce-span-in-default.rs:5:12
    |
 LL | #![feature(return_position_impl_trait_in_trait)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.stderr b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.next.stderr
index 7c7ebcdb7e7..05c025cc169 100644
--- a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.stderr
+++ b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.next.stderr
@@ -1,5 +1,5 @@
 warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/default-method-binder-shifting.rs:3:12
+  --> $DIR/box-coerce-span-in-default.rs:5:12
    |
 LL | #![feature(return_position_impl_trait_in_trait)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs
index a4d483dee7a..163bb4fcf77 100644
--- a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs
+++ b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs
@@ -1,4 +1,6 @@
 // check-pass
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(return_position_impl_trait_in_trait)]
 //~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete
diff --git a/tests/ui/impl-trait/in-trait/deep-match-works.rs b/tests/ui/impl-trait/in-trait/deep-match-works.rs
index 772da845ee1..5c9d2e356fc 100644
--- a/tests/ui/impl-trait/in-trait/deep-match-works.rs
+++ b/tests/ui/impl-trait/in-trait/deep-match-works.rs
@@ -1,4 +1,6 @@
 // check-pass
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
@@ -10,7 +12,9 @@ trait Foo {
 }
 
 impl Foo for () {
-    fn bar() -> Wrapper<i32> { Wrapper(0) }
+    fn bar() -> Wrapper<i32> {
+        Wrapper(0)
+    }
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/deep-match.stderr b/tests/ui/impl-trait/in-trait/deep-match.current.stderr
index 3eba419c0a3..400db20c79c 100644
--- a/tests/ui/impl-trait/in-trait/deep-match.stderr
+++ b/tests/ui/impl-trait/in-trait/deep-match.current.stderr
@@ -1,7 +1,7 @@
 error[E0053]: method `bar` has an incompatible return type for trait
-  --> $DIR/deep-match.rs:11:17
+  --> $DIR/deep-match.rs:14:17
    |
-LL |     fn bar() -> i32 { 0 }
+LL |     fn bar() -> i32 {
    |                 ^^^
    |                 |
    |                 expected `Wrapper<_>`, found `i32`
diff --git a/tests/ui/impl-trait/in-trait/deep-match.next.stderr b/tests/ui/impl-trait/in-trait/deep-match.next.stderr
new file mode 100644
index 00000000000..400db20c79c
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/deep-match.next.stderr
@@ -0,0 +1,15 @@
+error[E0053]: method `bar` has an incompatible return type for trait
+  --> $DIR/deep-match.rs:14:17
+   |
+LL |     fn bar() -> i32 {
+   |                 ^^^
+   |                 |
+   |                 expected `Wrapper<_>`, found `i32`
+   |                 return type in trait
+   |
+   = note: expected struct `Wrapper<_>`
+                found type `i32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/impl-trait/in-trait/deep-match.rs b/tests/ui/impl-trait/in-trait/deep-match.rs
index a6385147c3a..413d054e148 100644
--- a/tests/ui/impl-trait/in-trait/deep-match.rs
+++ b/tests/ui/impl-trait/in-trait/deep-match.rs
@@ -1,3 +1,6 @@
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
+
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
 
@@ -8,8 +11,10 @@ trait Foo {
 }
 
 impl Foo for () {
-    fn bar() -> i32 { 0 }
-    //~^ ERROR method `bar` has an incompatible return type for trait
+    fn bar() -> i32 {
+        //~^ ERROR method `bar` has an incompatible return type for trait
+        0
+    }
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err-2.current.stderr
index cc3bdf0e571..85450e3b0a0 100644
--- a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr
+++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.current.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/default-body-type-err-2.rs:8:9
+  --> $DIR/default-body-type-err-2.rs:10:9
    |
 LL |         42
    |         ^^- help: try using a conversion method: `.to_string()`
diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.next.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err-2.next.stderr
new file mode 100644
index 00000000000..85450e3b0a0
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.next.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/default-body-type-err-2.rs:10:9
+   |
+LL |         42
+   |         ^^- help: try using a conversion method: `.to_string()`
+   |         |
+   |         expected `String`, found integer
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs b/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs
index 45ae2b8ad3a..62323776310 100644
--- a/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs
+++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs
@@ -1,4 +1,6 @@
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![allow(incomplete_features)]
 #![feature(async_fn_in_trait)]
diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err.current.stderr
index 4742eb37d3e..c949168a377 100644
--- a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr
+++ b/tests/ui/impl-trait/in-trait/default-body-type-err.current.stderr
@@ -1,5 +1,5 @@
 error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String`
-  --> $DIR/default-body-type-err.rs:7:22
+  --> $DIR/default-body-type-err.rs:10:22
    |
 LL |     fn lol(&self) -> impl Deref<Target = String> {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `String`
diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.next.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err.next.stderr
new file mode 100644
index 00000000000..c949168a377
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/default-body-type-err.next.stderr
@@ -0,0 +1,12 @@
+error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String`
+  --> $DIR/default-body-type-err.rs:10:22
+   |
+LL |     fn lol(&self) -> impl Deref<Target = String> {
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `String`
+LL |
+LL |         &1i32
+   |         ----- return type was inferred to be `&i32` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.rs b/tests/ui/impl-trait/in-trait/default-body-type-err.rs
index ac9baf91cae..9bd5b777989 100644
--- a/tests/ui/impl-trait/in-trait/default-body-type-err.rs
+++ b/tests/ui/impl-trait/in-trait/default-body-type-err.rs
@@ -1,3 +1,6 @@
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
+
 #![allow(incomplete_features)]
 #![feature(return_position_impl_trait_in_trait)]
 
diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.current.stderr b/tests/ui/impl-trait/in-trait/default-body-with-rpit.current.stderr
new file mode 100644
index 00000000000..3c24eff9ae3
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.current.stderr
@@ -0,0 +1,24 @@
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/default-body-with-rpit.rs:13:9
+   |
+LL |         ""
+   |         ^^ expected `impl Debug`, got `&'static str`
+   |
+note: previous use here
+  --> $DIR/default-body-with-rpit.rs:12:39
+   |
+LL |       async fn baz(&self) -> impl Debug {
+   |  _______________________________________^
+LL | |         ""
+LL | |     }
+   | |_____^
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/default-body-with-rpit.rs:12:28
+   |
+LL |     async fn baz(&self) -> impl Debug {
+   |                            ^^^^^^^^^^ cannot resolve opaque type
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr b/tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr
new file mode 100644
index 00000000000..3c24eff9ae3
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr
@@ -0,0 +1,24 @@
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/default-body-with-rpit.rs:13:9
+   |
+LL |         ""
+   |         ^^ expected `impl Debug`, got `&'static str`
+   |
+note: previous use here
+  --> $DIR/default-body-with-rpit.rs:12:39
+   |
+LL |       async fn baz(&self) -> impl Debug {
+   |  _______________________________________^
+LL | |         ""
+LL | |     }
+   | |_____^
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/default-body-with-rpit.rs:12:28
+   |
+LL |     async fn baz(&self) -> impl Debug {
+   |                            ^^^^^^^^^^ cannot resolve opaque type
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
index ad3cc7c2524..6bcc7b9ef95 100644
--- a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
+++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
@@ -1,5 +1,7 @@
-// check-pass
 // edition:2021
+// known-bug: #108304
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/impl-trait/in-trait/default-body.rs b/tests/ui/impl-trait/in-trait/default-body.rs
index b0baf5bb10d..ab6a51c6bcb 100644
--- a/tests/ui/impl-trait/in-trait/default-body.rs
+++ b/tests/ui/impl-trait/in-trait/default-body.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.current.stderr b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.current.stderr
new file mode 100644
index 00000000000..a0c0589b9a1
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.current.stderr
@@ -0,0 +1,11 @@
+warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/default-method-binder-shifting.rs:5:12
+   |
+LL | #![feature(return_position_impl_trait_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.next.stderr b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.next.stderr
new file mode 100644
index 00000000000..a0c0589b9a1
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.next.stderr
@@ -0,0 +1,11 @@
+warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/default-method-binder-shifting.rs:5:12
+   |
+LL | #![feature(return_position_impl_trait_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs
index 5cf90c5d93c..de82544f293 100644
--- a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs
+++ b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs
@@ -1,4 +1,6 @@
 // check-pass
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(return_position_impl_trait_in_trait)]
 //~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete
@@ -11,4 +13,10 @@ trait Trait {
     fn method(&self) -> impl Trait<Type = impl Sized + '_>;
 }
 
+trait Trait2 {
+    type Type;
+
+    fn method(&self) -> impl Trait2<Type = impl Trait2<Type = impl Sized + '_> + '_>;
+}
+
 fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/default-method-constraint.stderr b/tests/ui/impl-trait/in-trait/default-method-constraint.current.stderr
index 5e18605aa4c..7bb79911f56 100644
--- a/tests/ui/impl-trait/in-trait/default-method-constraint.stderr
+++ b/tests/ui/impl-trait/in-trait/default-method-constraint.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/default-method-constraint.rs:5:12
+  --> $DIR/default-method-constraint.rs:7:12
    |
 LL | #![feature(return_position_impl_trait_in_trait)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/impl-trait/in-trait/default-method-constraint.next.stderr b/tests/ui/impl-trait/in-trait/default-method-constraint.next.stderr
new file mode 100644
index 00000000000..7bb79911f56
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/default-method-constraint.next.stderr
@@ -0,0 +1,11 @@
+warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/default-method-constraint.rs:7:12
+   |
+LL | #![feature(return_position_impl_trait_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/impl-trait/in-trait/default-method-constraint.rs b/tests/ui/impl-trait/in-trait/default-method-constraint.rs
index 8c50cc29586..e85fe3c8626 100644
--- a/tests/ui/impl-trait/in-trait/default-method-constraint.rs
+++ b/tests/ui/impl-trait/in-trait/default-method-constraint.rs
@@ -1,4 +1,6 @@
 // check-pass
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 // This didn't work in the previous default RPITIT method hack attempt
 
diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.current.stderr
index aa5492d285e..653016cf009 100644
--- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr
+++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.current.stderr
@@ -1,5 +1,5 @@
 error[E0277]: `()` doesn't implement `std::fmt::Display`
-  --> $DIR/doesnt-satisfy.rs:9:17
+  --> $DIR/doesnt-satisfy.rs:12:17
    |
 LL |     fn bar() -> () {}
    |                 ^^ `()` cannot be formatted with the default formatter
@@ -7,7 +7,7 @@ LL |     fn bar() -> () {}
    = help: the trait `std::fmt::Display` is not implemented for `()`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 note: required by a bound in `Foo::bar::{opaque#0}`
-  --> $DIR/doesnt-satisfy.rs:5:22
+  --> $DIR/doesnt-satisfy.rs:8:22
    |
 LL |     fn bar() -> impl std::fmt::Display;
    |                      ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::bar::{opaque#0}`
diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr
new file mode 100644
index 00000000000..bbfa089ceef
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr
@@ -0,0 +1,17 @@
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+  --> $DIR/doesnt-satisfy.rs:12:17
+   |
+LL |     fn bar() -> () {}
+   |                 ^^ `()` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `()`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `Foo::{opaque#0}`
+  --> $DIR/doesnt-satisfy.rs:8:22
+   |
+LL |     fn bar() -> impl std::fmt::Display;
+   |                      ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs
index bb4e0d44f3e..fcd0b51eea4 100644
--- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs
+++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs
@@ -1,3 +1,6 @@
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
+
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
 
diff --git a/tests/ui/impl-trait/in-trait/early.rs b/tests/ui/impl-trait/in-trait/early.rs
index 9c1c2b50339..831033a5880 100644
--- a/tests/ui/impl-trait/in-trait/early.rs
+++ b/tests/ui/impl-trait/in-trait/early.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/impl-trait/in-trait/encode.rs b/tests/ui/impl-trait/in-trait/encode.rs
index efb9f6498ba..98aaf4a6553 100644
--- a/tests/ui/impl-trait/in-trait/encode.rs
+++ b/tests/ui/impl-trait/in-trait/encode.rs
@@ -1,5 +1,7 @@
 // build-pass
 // compile-flags: --crate-type=lib
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/impl-trait/in-trait/foreign.rs b/tests/ui/impl-trait/in-trait/foreign.rs
index 6341f5b4284..df77372aabd 100644
--- a/tests/ui/impl-trait/in-trait/foreign.rs
+++ b/tests/ui/impl-trait/in-trait/foreign.rs
@@ -1,5 +1,7 @@
 // check-pass
 // aux-build: rpitit.rs
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 extern crate rpitit;
 
diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.current.stderr
index cd42683e022..310edbcb6cd 100644
--- a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr
+++ b/tests/ui/impl-trait/in-trait/generics-mismatch.current.stderr
@@ -1,5 +1,5 @@
 error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters
-  --> $DIR/generics-mismatch.rs:11:12
+  --> $DIR/generics-mismatch.rs:14:12
    |
 LL |     fn bar(&self) -> impl Sized;
    |           - expected 0 type parameters
diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr
new file mode 100644
index 00000000000..310edbcb6cd
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr
@@ -0,0 +1,12 @@
+error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters
+  --> $DIR/generics-mismatch.rs:14:12
+   |
+LL |     fn bar(&self) -> impl Sized;
+   |           - expected 0 type parameters
+...
+LL |     fn bar<T>(&self) {}
+   |            ^ found 1 type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0049`.
diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.rs b/tests/ui/impl-trait/in-trait/generics-mismatch.rs
index cc0fc720ebb..9259ca193d1 100644
--- a/tests/ui/impl-trait/in-trait/generics-mismatch.rs
+++ b/tests/ui/impl-trait/in-trait/generics-mismatch.rs
@@ -1,3 +1,6 @@
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
+
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
 
diff --git a/tests/ui/impl-trait/in-trait/issue-102140.stderr b/tests/ui/impl-trait/in-trait/issue-102140.current.stderr
index 18bb63745d7..7aa7880e258 100644
--- a/tests/ui/impl-trait/in-trait/issue-102140.stderr
+++ b/tests/ui/impl-trait/in-trait/issue-102140.current.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
-  --> $DIR/issue-102140.rs:23:22
+  --> $DIR/issue-102140.rs:26:22
    |
 LL |         MyTrait::foo(&self)
    |         ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
@@ -13,7 +13,7 @@ LL +         MyTrait::foo(self)
    |
 
 error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
-  --> $DIR/issue-102140.rs:23:9
+  --> $DIR/issue-102140.rs:26:9
    |
 LL |         MyTrait::foo(&self)
    |         ^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
@@ -21,7 +21,7 @@ LL |         MyTrait::foo(&self)
    = help: the trait `MyTrait` is implemented for `Outer`
 
 error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
-  --> $DIR/issue-102140.rs:23:9
+  --> $DIR/issue-102140.rs:26:9
    |
 LL |         MyTrait::foo(&self)
    |         ^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
diff --git a/tests/ui/impl-trait/in-trait/issue-102140.next.stderr b/tests/ui/impl-trait/in-trait/issue-102140.next.stderr
new file mode 100644
index 00000000000..7aa7880e258
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/issue-102140.next.stderr
@@ -0,0 +1,33 @@
+error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
+  --> $DIR/issue-102140.rs:26:22
+   |
+LL |         MyTrait::foo(&self)
+   |         ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
+   |         |
+   |         required by a bound introduced by this call
+   |
+help: consider removing the leading `&`-reference
+   |
+LL -         MyTrait::foo(&self)
+LL +         MyTrait::foo(self)
+   |
+
+error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
+  --> $DIR/issue-102140.rs:26:9
+   |
+LL |         MyTrait::foo(&self)
+   |         ^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
+   |
+   = help: the trait `MyTrait` is implemented for `Outer`
+
+error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
+  --> $DIR/issue-102140.rs:26:9
+   |
+LL |         MyTrait::foo(&self)
+   |         ^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
+   |
+   = help: the trait `MyTrait` is implemented for `Outer`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/in-trait/issue-102140.rs b/tests/ui/impl-trait/in-trait/issue-102140.rs
index be1e012acb1..4dcac4f5b0e 100644
--- a/tests/ui/impl-trait/in-trait/issue-102140.rs
+++ b/tests/ui/impl-trait/in-trait/issue-102140.rs
@@ -1,3 +1,6 @@
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
+
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
 
diff --git a/tests/ui/impl-trait/in-trait/issue-102301.rs b/tests/ui/impl-trait/in-trait/issue-102301.rs
index a93714a658e..1329ca29d06 100644
--- a/tests/ui/impl-trait/in-trait/issue-102301.rs
+++ b/tests/ui/impl-trait/in-trait/issue-102301.rs
@@ -1,4 +1,6 @@
 // check-pass
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/impl-trait/in-trait/issue-102571.stderr b/tests/ui/impl-trait/in-trait/issue-102571.current.stderr
index 87219941d91..cac9a29f644 100644
--- a/tests/ui/impl-trait/in-trait/issue-102571.stderr
+++ b/tests/ui/impl-trait/in-trait/issue-102571.current.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-102571.rs:20:9
+  --> $DIR/issue-102571.rs:23:9
    |
 LL |     let () = t.bar();
    |         ^^   ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>`
diff --git a/tests/ui/impl-trait/in-trait/issue-102571.next.stderr b/tests/ui/impl-trait/in-trait/issue-102571.next.stderr
new file mode 100644
index 00000000000..cac9a29f644
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/issue-102571.next.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-102571.rs:23:9
+   |
+LL |     let () = t.bar();
+   |         ^^   ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>`
+   |         |
+   |         expected associated type, found `()`
+   |
+   = note: expected associated type `impl Deref<Target = impl std::fmt::Display + ?Sized>`
+                    found unit type `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/impl-trait/in-trait/issue-102571.rs b/tests/ui/impl-trait/in-trait/issue-102571.rs
index 61c91e64417..f0ddab5e7f2 100644
--- a/tests/ui/impl-trait/in-trait/issue-102571.rs
+++ b/tests/ui/impl-trait/in-trait/issue-102571.rs
@@ -1,3 +1,6 @@
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
+
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
 
diff --git a/tests/ui/impl-trait/in-trait/new-lowering-strategy/simple-impl-trait.rs b/tests/ui/impl-trait/in-trait/new-lowering-strategy/simple-impl-trait.rs
deleted file mode 100644
index ae09d20f6f5..00000000000
--- a/tests/ui/impl-trait/in-trait/new-lowering-strategy/simple-impl-trait.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// check-pass
-// compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
-
-#![feature(return_position_impl_trait_in_trait)]
-#![allow(incomplete_features)]
-
-trait Foo {
-    fn foo() -> impl Sized;
-}
-
-impl Foo for String {
-    fn foo() -> i32 {
-        22
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/new-lowering-strategy/simple-trait.rs b/tests/ui/impl-trait/in-trait/new-lowering-strategy/simple-trait.rs
deleted file mode 100644
index dfce973d770..00000000000
--- a/tests/ui/impl-trait/in-trait/new-lowering-strategy/simple-trait.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// check-pass
-// compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
-
-#![feature(return_position_impl_trait_in_trait)]
-#![allow(incomplete_features)]
-
-trait Foo {
-    fn foo() -> impl Sized;
-}
-
-fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/object-safety.current.stderr
index ca0e760ff6d..b7f2b019a77 100644
--- a/tests/ui/impl-trait/in-trait/object-safety.stderr
+++ b/tests/ui/impl-trait/in-trait/object-safety.current.stderr
@@ -1,11 +1,11 @@
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety.rs:17:33
+  --> $DIR/object-safety.rs:20:33
    |
 LL |     let i = Box::new(42_u32) as Box<dyn Foo>;
    |                                 ^^^^^^^^^^^^ `Foo` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/object-safety.rs:7:22
+  --> $DIR/object-safety.rs:10:22
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
@@ -14,13 +14,13 @@ LL |     fn baz(&self) -> impl Debug;
    = help: consider moving `baz` to another trait
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety.rs:20:13
+  --> $DIR/object-safety.rs:23:13
    |
 LL |     let s = i.baz();
    |             ^^^^^^^ `Foo` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/object-safety.rs:7:22
+  --> $DIR/object-safety.rs:10:22
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
@@ -29,13 +29,13 @@ LL |     fn baz(&self) -> impl Debug;
    = help: consider moving `baz` to another trait
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety.rs:17:13
+  --> $DIR/object-safety.rs:20:13
    |
 LL |     let i = Box::new(42_u32) as Box<dyn Foo>;
    |             ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/object-safety.rs:7:22
+  --> $DIR/object-safety.rs:10:22
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
diff --git a/tests/ui/impl-trait/in-trait/object-safety.next.stderr b/tests/ui/impl-trait/in-trait/object-safety.next.stderr
new file mode 100644
index 00000000000..b7f2b019a77
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/object-safety.next.stderr
@@ -0,0 +1,50 @@
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/object-safety.rs:20:33
+   |
+LL |     let i = Box::new(42_u32) as Box<dyn Foo>;
+   |                                 ^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety.rs:10:22
+   |
+LL | trait Foo {
+   |       --- this trait cannot be made into an object...
+LL |     fn baz(&self) -> impl Debug;
+   |                      ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
+   = help: consider moving `baz` to another trait
+
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/object-safety.rs:23:13
+   |
+LL |     let s = i.baz();
+   |             ^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety.rs:10:22
+   |
+LL | trait Foo {
+   |       --- this trait cannot be made into an object...
+LL |     fn baz(&self) -> impl Debug;
+   |                      ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
+   = help: consider moving `baz` to another trait
+
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/object-safety.rs:20:13
+   |
+LL |     let i = Box::new(42_u32) as Box<dyn Foo>;
+   |             ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety.rs:10:22
+   |
+LL | trait Foo {
+   |       --- this trait cannot be made into an object...
+LL |     fn baz(&self) -> impl Debug;
+   |                      ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
+   = help: consider moving `baz` to another trait
+   = note: required for `Box<u32>` to implement `CoerceUnsized<Box<dyn Foo>>`
+   = note: required by cast to type `Box<dyn Foo>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs
index dd35b9a2d8a..016a0aaae4b 100644
--- a/tests/ui/impl-trait/in-trait/object-safety.rs
+++ b/tests/ui/impl-trait/in-trait/object-safety.rs
@@ -1,3 +1,6 @@
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
+
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
 
diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.current.stderr
index 15edda48340..a57653b2c9e 100644
--- a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr
+++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.current.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/opaque-in-impl-is-opaque.rs:17:19
+  --> $DIR/opaque-in-impl-is-opaque.rs:20:19
    |
 LL |     fn bar(&self) -> impl Display {
    |                      ------------ the found opaque type
diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.next.stderr b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.next.stderr
new file mode 100644
index 00000000000..a57653b2c9e
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.next.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/opaque-in-impl-is-opaque.rs:20:19
+   |
+LL |     fn bar(&self) -> impl Display {
+   |                      ------------ the found opaque type
+...
+LL |     let x: &str = ().bar();
+   |            ----   ^^^^^^^^ expected `&str`, found opaque type
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&str`
+            found opaque type `impl std::fmt::Display`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
index 3ac264e8eba..c07ece15a83 100644
--- a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
+++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
@@ -1,3 +1,6 @@
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
+
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
 
diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl.rs b/tests/ui/impl-trait/in-trait/opaque-in-impl.rs
index 2e06629699a..f48d9fa26c0 100644
--- a/tests/ui/impl-trait/in-trait/opaque-in-impl.rs
+++ b/tests/ui/impl-trait/in-trait/opaque-in-impl.rs
@@ -1,4 +1,6 @@
 // check-pass
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/impl-trait/in-trait/reveal.rs b/tests/ui/impl-trait/in-trait/reveal.rs
index d6ede1cc495..1f42ec744db 100644
--- a/tests/ui/impl-trait/in-trait/reveal.rs
+++ b/tests/ui/impl-trait/in-trait/reveal.rs
@@ -1,4 +1,6 @@
 // check-pass
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.stderr b/tests/ui/impl-trait/in-trait/signature-mismatch.current.stderr
index c4fcaabe446..eba270af7f0 100644
--- a/tests/ui/impl-trait/in-trait/signature-mismatch.stderr
+++ b/tests/ui/impl-trait/in-trait/signature-mismatch.current.stderr
@@ -1,5 +1,5 @@
 error: `impl` item signature doesn't match `trait` item signature
-  --> $DIR/signature-mismatch.rs:15:5
+  --> $DIR/signature-mismatch.rs:17:5
    |
 LL |     fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>;
    |     ----------------------------------------------------------------- expected `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '3`
diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.next.stderr b/tests/ui/impl-trait/in-trait/signature-mismatch.next.stderr
new file mode 100644
index 00000000000..eba270af7f0
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/signature-mismatch.next.stderr
@@ -0,0 +1,16 @@
+error: `impl` item signature doesn't match `trait` item signature
+  --> $DIR/signature-mismatch.rs:17:5
+   |
+LL |     fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>;
+   |     ----------------------------------------------------------------- expected `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '3`
+...
+LL |     fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
+   |
+   = note: expected signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '3`
+              found signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
+
+error: aborting due to previous error
+
diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.rs b/tests/ui/impl-trait/in-trait/signature-mismatch.rs
index 90682631aa0..38c902a97a9 100644
--- a/tests/ui/impl-trait/in-trait/signature-mismatch.rs
+++ b/tests/ui/impl-trait/in-trait/signature-mismatch.rs
@@ -1,4 +1,6 @@
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.current.stderr
index dc621d6b8a8..f48e7a1ed14 100644
--- a/tests/ui/impl-trait/in-trait/specialization-broken.stderr
+++ b/tests/ui/impl-trait/in-trait/specialization-broken.current.stderr
@@ -1,5 +1,5 @@
 error[E0053]: method `bar` has an incompatible type for trait
-  --> $DIR/specialization-broken.rs:16:22
+  --> $DIR/specialization-broken.rs:19:22
    |
 LL | default impl<U> Foo for U
    |              - this type parameter
@@ -11,7 +11,7 @@ LL |     fn bar(&self) -> U {
    |                      help: change the output type to match the trait: `impl Sized`
    |
 note: type in trait
-  --> $DIR/specialization-broken.rs:9:22
+  --> $DIR/specialization-broken.rs:12:22
    |
 LL |     fn bar(&self) -> impl Sized;
    |                      ^^^^^^^^^^
@@ -19,7 +19,7 @@ LL |     fn bar(&self) -> impl Sized;
               found signature `fn(&U) -> U`
 
 error: method with return-position `impl Trait` in trait cannot be specialized
-  --> $DIR/specialization-broken.rs:16:5
+  --> $DIR/specialization-broken.rs:19:5
    |
 LL |     fn bar(&self) -> U {
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.next.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.next.stderr
new file mode 100644
index 00000000000..f48e7a1ed14
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/specialization-broken.next.stderr
@@ -0,0 +1,31 @@
+error[E0053]: method `bar` has an incompatible type for trait
+  --> $DIR/specialization-broken.rs:19:22
+   |
+LL | default impl<U> Foo for U
+   |              - this type parameter
+...
+LL |     fn bar(&self) -> U {
+   |                      ^
+   |                      |
+   |                      expected associated type, found type parameter `U`
+   |                      help: change the output type to match the trait: `impl Sized`
+   |
+note: type in trait
+  --> $DIR/specialization-broken.rs:12:22
+   |
+LL |     fn bar(&self) -> impl Sized;
+   |                      ^^^^^^^^^^
+   = note: expected signature `fn(&U) -> impl Sized`
+              found signature `fn(&U) -> U`
+
+error: method with return-position `impl Trait` in trait cannot be specialized
+  --> $DIR/specialization-broken.rs:19:5
+   |
+LL |     fn bar(&self) -> U {
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: specialization behaves in inconsistent and surprising ways with `#![feature(return_position_impl_trait_in_trait)]`, and for now is disallowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.rs b/tests/ui/impl-trait/in-trait/specialization-broken.rs
index 2fcffdf3f9a..658d0709717 100644
--- a/tests/ui/impl-trait/in-trait/specialization-broken.rs
+++ b/tests/ui/impl-trait/in-trait/specialization-broken.rs
@@ -1,3 +1,6 @@
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
+
 // FIXME(compiler-errors): I'm not exactly sure if this is expected to pass or not.
 // But we fixed an ICE anyways.
 
diff --git a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs
index c9ee877db8e..dbc5d38f192 100644
--- a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs
+++ b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs
@@ -1,4 +1,6 @@
 // check-pass
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(specialization)]
 #![feature(return_position_impl_trait_in_trait)]
diff --git a/tests/ui/impl-trait/in-trait/success.rs b/tests/ui/impl-trait/in-trait/success.rs
index 4cbe682b46f..0e69e0490c7 100644
--- a/tests/ui/impl-trait/in-trait/success.rs
+++ b/tests/ui/impl-trait/in-trait/success.rs
@@ -1,4 +1,6 @@
 // check-pass
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.current.stderr
index 8ff54cad951..64c942705cf 100644
--- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
+++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.current.stderr
@@ -1,5 +1,5 @@
 error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter
-  --> $DIR/trait-more-generics-than-impl.rs:11:11
+  --> $DIR/trait-more-generics-than-impl.rs:14:11
    |
 LL |     fn bar<T>() -> impl Sized;
    |            - expected 1 type parameter
diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.next.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.next.stderr
new file mode 100644
index 00000000000..64c942705cf
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.next.stderr
@@ -0,0 +1,12 @@
+error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter
+  --> $DIR/trait-more-generics-than-impl.rs:14:11
+   |
+LL |     fn bar<T>() -> impl Sized;
+   |            - expected 1 type parameter
+...
+LL |     fn bar() -> impl Sized {}
+   |           ^ found 0 type parameters
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0049`.
diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
index 0bbe50ea6fd..c2e394a1f66 100644
--- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
+++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
@@ -1,3 +1,6 @@
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
+
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
 
diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.current.stderr
index 03cc4c2b93b..8392f26e7c8 100644
--- a/tests/ui/impl-trait/in-trait/wf-bounds.stderr
+++ b/tests/ui/impl-trait/in-trait/wf-bounds.current.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/wf-bounds.rs:9:22
+  --> $DIR/wf-bounds.rs:11:22
    |
 LL |     fn nya() -> impl Wf<Vec<[u8]>>;
    |                      ^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -9,14 +9,14 @@ note: required by a bound in `Vec`
   --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/wf-bounds.rs:12:23
+  --> $DIR/wf-bounds.rs:14:23
    |
 LL |     fn nya2() -> impl Wf<[u8]>;
    |                       ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[u8]`
 note: required by a bound in `Wf`
-  --> $DIR/wf-bounds.rs:6:10
+  --> $DIR/wf-bounds.rs:8:10
    |
 LL | trait Wf<T> {}
    |          ^ required by this bound in `Wf`
diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr
new file mode 100644
index 00000000000..8392f26e7c8
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr
@@ -0,0 +1,30 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/wf-bounds.rs:11:22
+   |
+LL |     fn nya() -> impl Wf<Vec<[u8]>>;
+   |                      ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `Vec`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/wf-bounds.rs:14:23
+   |
+LL |     fn nya2() -> impl Wf<[u8]>;
+   |                       ^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `Wf`
+  --> $DIR/wf-bounds.rs:8:10
+   |
+LL | trait Wf<T> {}
+   |          ^ required by this bound in `Wf`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait Wf<T: ?Sized> {}
+   |           ++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.rs b/tests/ui/impl-trait/in-trait/wf-bounds.rs
index 2c71583b312..39f41275315 100644
--- a/tests/ui/impl-trait/in-trait/wf-bounds.rs
+++ b/tests/ui/impl-trait/in-trait/wf-bounds.rs
@@ -1,4 +1,6 @@
 // issue #101663
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/impl-trait/in-trait/where-clause.rs b/tests/ui/impl-trait/in-trait/where-clause.rs
index 87bac519cf3..88d86e2b541 100644
--- a/tests/ui/impl-trait/in-trait/where-clause.rs
+++ b/tests/ui/impl-trait/in-trait/where-clause.rs
@@ -1,5 +1,7 @@
 // check-pass
 // edition: 2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/impl-trait/issues/issue-78722.rs b/tests/ui/impl-trait/issues/issue-78722.rs
index 78233f300bd..7b5ab5f2298 100644
--- a/tests/ui/impl-trait/issues/issue-78722.rs
+++ b/tests/ui/impl-trait/issues/issue-78722.rs
@@ -12,7 +12,6 @@ struct Bug {
         }
         let f: F = async { 1 };
         //~^ ERROR `async` blocks are not allowed in constants
-        //~| ERROR destructor of
         1
     }],
 }
diff --git a/tests/ui/impl-trait/issues/issue-78722.stderr b/tests/ui/impl-trait/issues/issue-78722.stderr
index c00df8087e8..05a2c135cf7 100644
--- a/tests/ui/impl-trait/issues/issue-78722.stderr
+++ b/tests/ui/impl-trait/issues/issue-78722.stderr
@@ -7,22 +7,13 @@ LL |         let f: F = async { 1 };
    = note: see issue #85368 <https://github.com/rust-lang/rust/issues/85368> for more information
    = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable
 
-error[E0493]: destructor of `F` cannot be evaluated at compile-time
-  --> $DIR/issue-78722.rs:13:13
-   |
-LL |         let f: F = async { 1 };
-   |             ^ the destructor for this type cannot be evaluated in constants
-...
-LL |     }],
-   |     - value is dropped here
-
 error[E0271]: expected `[async block@$DIR/issue-78722.rs:11:13: 11:21]` to be a future that resolves to `u8`, but it resolves to `()`
   --> $DIR/issue-78722.rs:9:30
    |
 LL |         fn concrete_use() -> F {
    |                              ^ expected `()`, found `u8`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0271, E0493, E0658.
+Some errors have detailed explanations: E0271, E0658.
 For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/imports/issue-99695-b.fixed b/tests/ui/imports/issue-99695-b.fixed
index 0e60c73b67a..0f688fa2823 100644
--- a/tests/ui/imports/issue-99695-b.fixed
+++ b/tests/ui/imports/issue-99695-b.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, nonstandard_style)]
+#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
 mod m {
 
     mod p {
diff --git a/tests/ui/imports/issue-99695-b.rs b/tests/ui/imports/issue-99695-b.rs
index 031443a1f5d..b433997e53f 100644
--- a/tests/ui/imports/issue-99695-b.rs
+++ b/tests/ui/imports/issue-99695-b.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, nonstandard_style)]
+#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
 mod m {
 
     mod p {
diff --git a/tests/ui/imports/issue-99695.fixed b/tests/ui/imports/issue-99695.fixed
index 6bf228b23aa..17ff409324e 100644
--- a/tests/ui/imports/issue-99695.fixed
+++ b/tests/ui/imports/issue-99695.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, nonstandard_style)]
+#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
 mod m {
     #[macro_export]
     macro_rules! nu {
diff --git a/tests/ui/imports/issue-99695.rs b/tests/ui/imports/issue-99695.rs
index f7199f1497a..b8979bcb734 100644
--- a/tests/ui/imports/issue-99695.rs
+++ b/tests/ui/imports/issue-99695.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, nonstandard_style)]
+#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
 mod m {
     #[macro_export]
     macro_rules! nu {
diff --git a/tests/ui/issues/issue-19086.stderr b/tests/ui/issues/issue-19086.stderr
index a3c06a72511..90d0bb40655 100644
--- a/tests/ui/issues/issue-19086.stderr
+++ b/tests/ui/issues/issue-19086.stderr
@@ -5,7 +5,7 @@ LL |     FooB { x: i32, y: i32 }
    |     ----------------------- `FooB` defined here
 ...
 LL |         FooB(a, b) => println!("{} {}", a, b),
-   |         ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }`
+   |         ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x: a, y: b }`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issues/issue-20413.stderr b/tests/ui/issues/issue-20413.stderr
index 202e8463145..8891a26784e 100644
--- a/tests/ui/issues/issue-20413.stderr
+++ b/tests/ui/issues/issue-20413.stderr
@@ -20,51 +20,51 @@ note: required for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoDa
 LL | impl<T> Foo for T where NoData<T>: Foo {
    |         ^^^     ^                  --- unsatisfied trait bound introduced here
    = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
-   = note: 127 redundant requirements hidden
+   = note: 126 redundant requirements hidden
    = note: required for `NoData<T>` to implement `Foo`
 
-error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>: Baz`
+error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>: Bar`
   --> $DIR/issue-20413.rs:28:42
    |
 LL | impl<T> Bar for T where EvenLessData<T>: Baz {
    |                                          ^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`)
-note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar`
-  --> $DIR/issue-20413.rs:28:9
-   |
-LL | impl<T> Bar for T where EvenLessData<T>: Baz {
-   |         ^^^     ^                        --- unsatisfied trait bound introduced here
-   = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
 note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz`
   --> $DIR/issue-20413.rs:35:9
    |
 LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
    |         ^^^     ^                        --- unsatisfied trait bound introduced here
    = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
-   = note: 126 redundant requirements hidden
+note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar`
+  --> $DIR/issue-20413.rs:28:9
+   |
+LL | impl<T> Bar for T where EvenLessData<T>: Baz {
+   |         ^^^     ^                        --- unsatisfied trait bound introduced here
+   = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
+   = note: 125 redundant requirements hidden
    = note: required for `EvenLessData<T>` to implement `Baz`
 
-error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>: Bar`
+error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>: Baz`
   --> $DIR/issue-20413.rs:35:42
    |
 LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
    |                                          ^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`)
-note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz`
-  --> $DIR/issue-20413.rs:35:9
-   |
-LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
-   |         ^^^     ^                        --- unsatisfied trait bound introduced here
-   = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
 note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar`
   --> $DIR/issue-20413.rs:28:9
    |
 LL | impl<T> Bar for T where EvenLessData<T>: Baz {
    |         ^^^     ^                        --- unsatisfied trait bound introduced here
    = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
-   = note: 126 redundant requirements hidden
+note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz`
+  --> $DIR/issue-20413.rs:35:9
+   |
+LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
+   |         ^^^     ^                        --- unsatisfied trait bound introduced here
+   = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
+   = note: 125 redundant requirements hidden
    = note: required for `AlmostNoData<T>` to implement `Bar`
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/late-bound-lifetimes/issue-80618.rs b/tests/ui/late-bound-lifetimes/issue-80618.rs
new file mode 100644
index 00000000000..6aa8ff461a9
--- /dev/null
+++ b/tests/ui/late-bound-lifetimes/issue-80618.rs
@@ -0,0 +1,8 @@
+fn foo<'a>(x: &'a str) -> &'a str {
+    x
+}
+
+fn main() {
+    let _ = foo::<'static>;
+//~^ ERROR cannot specify lifetime arguments explicitly if late bound lifetime parameters are present [E0794]
+}
diff --git a/tests/ui/late-bound-lifetimes/issue-80618.stderr b/tests/ui/late-bound-lifetimes/issue-80618.stderr
new file mode 100644
index 00000000000..cf7423fc16f
--- /dev/null
+++ b/tests/ui/late-bound-lifetimes/issue-80618.stderr
@@ -0,0 +1,15 @@
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/issue-80618.rs:6:19
+   |
+LL |     let _ = foo::<'static>;
+   |                   ^^^^^^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/issue-80618.rs:1:8
+   |
+LL | fn foo<'a>(x: &'a str) -> &'a str {
+   |        ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0794`.
diff --git a/tests/ui/layout/transmute-to-tail-with-err.rs b/tests/ui/layout/transmute-to-tail-with-err.rs
new file mode 100644
index 00000000000..6753ce15ed1
--- /dev/null
+++ b/tests/ui/layout/transmute-to-tail-with-err.rs
@@ -0,0 +1,8 @@
+trait Trait<T> {}
+
+struct Bar(Box<dyn Trait<T>>);
+//~^ ERROR cannot find type `T` in this scope
+
+fn main() {
+    let x: Bar = unsafe { std::mem::transmute(()) };
+}
diff --git a/tests/ui/layout/transmute-to-tail-with-err.stderr b/tests/ui/layout/transmute-to-tail-with-err.stderr
new file mode 100644
index 00000000000..97ab59c398a
--- /dev/null
+++ b/tests/ui/layout/transmute-to-tail-with-err.stderr
@@ -0,0 +1,14 @@
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/transmute-to-tail-with-err.rs:3:26
+   |
+LL | struct Bar(Box<dyn Trait<T>>);
+   |                          ^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | struct Bar<T>(Box<dyn Trait<T>>);
+   |           +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/lifetimes/unusual-rib-combinations.rs b/tests/ui/lifetimes/unusual-rib-combinations.rs
index 1c122f42e59..0ae68ad04f7 100644
--- a/tests/ui/lifetimes/unusual-rib-combinations.rs
+++ b/tests/ui/lifetimes/unusual-rib-combinations.rs
@@ -25,4 +25,9 @@ fn d<const C: S>() {}
 //~^ ERROR missing lifetime specifier
 //~| ERROR `S<'_>` is forbidden as the type of a const generic parameter
 
+trait Foo<'a> {}
+struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>;
+//~^ ERROR use of non-static lifetime `'a` in const generic
+//~| ERROR `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter
+
 fn main() {}
diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr
index 68f4fce0178..20163d289b1 100644
--- a/tests/ui/lifetimes/unusual-rib-combinations.stderr
+++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr
@@ -9,6 +9,14 @@ help: consider introducing a named lifetime parameter
 LL | fn d<'a, const C: S<'a>>() {}
    |      +++           ++++
 
+error[E0771]: use of non-static lifetime `'a` in const generic
+  --> $DIR/unusual-rib-combinations.rs:29:22
+   |
+LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>;
+   |                      ^^
+   |
+   = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
+
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
   --> $DIR/unusual-rib-combinations.rs:7:16
    |
@@ -55,7 +63,16 @@ LL | fn d<const C: S>() {}
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error: aborting due to 7 previous errors
+error: `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter
+  --> $DIR/unusual-rib-combinations.rs:29:21
+   |
+LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>;
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = help: more complex types are supported with `#![feature(adt_const_params)]`
+
+error: aborting due to 9 previous errors
 
-Some errors have detailed explanations: E0106, E0214, E0308.
+Some errors have detailed explanations: E0106, E0214, E0308, E0771.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/linkage-attr/issue-109144.rs b/tests/ui/linkage-attr/issue-109144.rs
new file mode 100644
index 00000000000..2f740e55389
--- /dev/null
+++ b/tests/ui/linkage-attr/issue-109144.rs
@@ -0,0 +1,4 @@
+#![crate_type = "lib"]
+#[link(kind = "static", modifiers = "+whole-archive,+bundle")]
+//~^ ERROR `#[link]` attribute requires a `name = "string"` argument
+extern  {}
diff --git a/tests/ui/linkage-attr/issue-109144.stderr b/tests/ui/linkage-attr/issue-109144.stderr
new file mode 100644
index 00000000000..33187cfdbb6
--- /dev/null
+++ b/tests/ui/linkage-attr/issue-109144.stderr
@@ -0,0 +1,9 @@
+error[E0459]: `#[link]` attribute requires a `name = "string"` argument
+  --> $DIR/issue-109144.rs:2:1
+   |
+LL | #[link(kind = "static", modifiers = "+whole-archive,+bundle")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `name` argument
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0459`.
diff --git a/tests/ui/lint/anonymous-reexport.rs b/tests/ui/lint/anonymous-reexport.rs
new file mode 100644
index 00000000000..5d56ae6f969
--- /dev/null
+++ b/tests/ui/lint/anonymous-reexport.rs
@@ -0,0 +1,21 @@
+#![deny(useless_anonymous_reexport)]
+#![crate_type = "rlib"]
+
+mod my_mod {
+    pub trait Foo {}
+    pub type TyFoo = dyn Foo;
+    pub struct Bar;
+    pub type TyBar = Bar;
+}
+
+pub use self::my_mod::Foo as _;
+pub use self::my_mod::TyFoo as _;
+pub use self::my_mod::Bar as _; //~ ERROR
+pub use self::my_mod::TyBar as _; //~ ERROR
+pub use self::my_mod::{Bar as _}; //~ ERROR
+pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR
+pub use self::my_mod::{Bar as _, TyBar as _};
+//~^ ERROR
+//~| ERROR
+#[allow(unused_imports)]
+use self::my_mod::TyBar as _;
diff --git a/tests/ui/lint/anonymous-reexport.stderr b/tests/ui/lint/anonymous-reexport.stderr
new file mode 100644
index 00000000000..f4f8b41c417
--- /dev/null
+++ b/tests/ui/lint/anonymous-reexport.stderr
@@ -0,0 +1,55 @@
+error: useless anonymous re-export
+  --> $DIR/anonymous-reexport.rs:13:1
+   |
+LL | pub use self::my_mod::Bar as _;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only anonymous re-exports of traits are useful, this is a `struct`
+note: the lint level is defined here
+  --> $DIR/anonymous-reexport.rs:1:9
+   |
+LL | #![deny(useless_anonymous_reexport)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: useless anonymous re-export
+  --> $DIR/anonymous-reexport.rs:14:1
+   |
+LL | pub use self::my_mod::TyBar as _;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only anonymous re-exports of traits are useful, this is a `type alias`
+
+error: useless anonymous re-export
+  --> $DIR/anonymous-reexport.rs:15:24
+   |
+LL | pub use self::my_mod::{Bar as _};
+   |                        ^^^^^^^^
+   |
+   = note: only anonymous re-exports of traits are useful, this is a `struct`
+
+error: useless anonymous re-export
+  --> $DIR/anonymous-reexport.rs:16:24
+   |
+LL | pub use self::my_mod::{Bar as _, Foo as _};
+   |                        ^^^^^^^^
+   |
+   = note: only anonymous re-exports of traits are useful, this is a `struct`
+
+error: useless anonymous re-export
+  --> $DIR/anonymous-reexport.rs:17:24
+   |
+LL | pub use self::my_mod::{Bar as _, TyBar as _};
+   |                        ^^^^^^^^
+   |
+   = note: only anonymous re-exports of traits are useful, this is a `struct`
+
+error: useless anonymous re-export
+  --> $DIR/anonymous-reexport.rs:17:34
+   |
+LL | pub use self::my_mod::{Bar as _, TyBar as _};
+   |                                  ^^^^^^^^^^
+   |
+   = note: only anonymous re-exports of traits are useful, this is a `type alias`
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs
index 809e0602671..09fda33dbec 100644
--- a/tests/ui/lint/clashing-extern-fn.rs
+++ b/tests/ui/lint/clashing-extern-fn.rs
@@ -122,8 +122,8 @@ mod banana {
             weight: u32,
             length: u16,
         } // note: distinct type
-          // This should not trigger the lint because two::Banana is structurally equivalent to
-          // one::Banana.
+        // This should not trigger the lint because two::Banana is structurally equivalent to
+        // one::Banana.
         extern "C" {
             fn weigh_banana(count: *const Banana) -> u64;
         }
@@ -223,6 +223,27 @@ mod transparent {
     }
 }
 
+#[allow(improper_ctypes)]
+mod zst {
+    mod transparent {
+        #[repr(transparent)]
+        struct TransparentZst(());
+        extern "C" {
+            fn zst() -> ();
+            fn transparent_zst() -> TransparentZst;
+        }
+    }
+
+    mod not_transparent {
+        struct NotTransparentZst(());
+        extern "C" {
+            // These shouldn't warn since all return types are zero sized
+            fn zst() -> NotTransparentZst;
+            fn transparent_zst() -> NotTransparentZst;
+        }
+    }
+}
+
 mod missing_return_type {
     mod a {
         extern "C" {
@@ -397,10 +418,14 @@ mod hidden_niche {
         use std::num::NonZeroUsize;
 
         #[repr(transparent)]
-        struct Transparent { x: NonZeroUsize }
+        struct Transparent {
+            x: NonZeroUsize,
+        }
 
         #[repr(transparent)]
-        struct TransparentNoNiche { y: UnsafeCell<NonZeroUsize> }
+        struct TransparentNoNiche {
+            y: UnsafeCell<NonZeroUsize>,
+        }
 
         extern "C" {
             fn hidden_niche_transparent() -> Option<Transparent>;
diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr
index 217eed6c92c..5d457ba0ec7 100644
--- a/tests/ui/lint/clashing-extern-fn.stderr
+++ b/tests/ui/lint/clashing-extern-fn.stderr
@@ -130,7 +130,7 @@ LL |             fn transparent_incorrect() -> isize;
               found `unsafe extern "C" fn() -> isize`
 
 warning: `missing_return_type` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:238:13
+  --> $DIR/clashing-extern-fn.rs:259:13
    |
 LL |             fn missing_return_type() -> usize;
    |             ---------------------------------- `missing_return_type` previously declared here
@@ -142,7 +142,7 @@ LL |             fn missing_return_type();
               found `unsafe extern "C" fn()`
 
 warning: `non_zero_usize` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:256:13
+  --> $DIR/clashing-extern-fn.rs:277:13
    |
 LL |             fn non_zero_usize() -> core::num::NonZeroUsize;
    |             ----------------------------------------------- `non_zero_usize` previously declared here
@@ -154,7 +154,7 @@ LL |             fn non_zero_usize() -> usize;
               found `unsafe extern "C" fn() -> usize`
 
 warning: `non_null_ptr` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:258:13
+  --> $DIR/clashing-extern-fn.rs:279:13
    |
 LL |             fn non_null_ptr() -> core::ptr::NonNull<usize>;
    |             ----------------------------------------------- `non_null_ptr` previously declared here
@@ -166,7 +166,7 @@ LL |             fn non_null_ptr() -> *const usize;
               found `unsafe extern "C" fn() -> *const usize`
 
 warning: `option_non_zero_usize_incorrect` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:356:13
+  --> $DIR/clashing-extern-fn.rs:377:13
    |
 LL |             fn option_non_zero_usize_incorrect() -> usize;
    |             ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
@@ -178,7 +178,7 @@ LL |             fn option_non_zero_usize_incorrect() -> isize;
               found `unsafe extern "C" fn() -> isize`
 
 warning: `option_non_null_ptr_incorrect` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:358:13
+  --> $DIR/clashing-extern-fn.rs:379:13
    |
 LL |             fn option_non_null_ptr_incorrect() -> *const usize;
    |             --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
@@ -190,7 +190,7 @@ LL |             fn option_non_null_ptr_incorrect() -> *const isize;
               found `unsafe extern "C" fn() -> *const isize`
 
 warning: `hidden_niche_transparent_no_niche` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:408:13
+  --> $DIR/clashing-extern-fn.rs:433:13
    |
 LL |             fn hidden_niche_transparent_no_niche() -> usize;
    |             ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here
@@ -202,7 +202,7 @@ LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
               found `unsafe extern "C" fn() -> Option<TransparentNoNiche>`
 
 warning: `hidden_niche_unsafe_cell` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:412:13
+  --> $DIR/clashing-extern-fn.rs:437:13
    |
 LL |             fn hidden_niche_unsafe_cell() -> usize;
    |             --------------------------------------- `hidden_niche_unsafe_cell` previously declared here
@@ -214,7 +214,7 @@ LL |             fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize
               found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZeroUsize>>`
 
 warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe
-  --> $DIR/clashing-extern-fn.rs:408:55
+  --> $DIR/clashing-extern-fn.rs:433:55
    |
 LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
    |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -224,7 +224,7 @@ LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
    = note: `#[warn(improper_ctypes)]` on by default
 
 warning: `extern` block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe
-  --> $DIR/clashing-extern-fn.rs:412:46
+  --> $DIR/clashing-extern-fn.rs:437:46
    |
 LL |             fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>;
    |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
diff --git a/tests/ui/lint/fn_must_use.stderr b/tests/ui/lint/fn_must_use.stderr
index 657f23c6085..e88c1a9b8a9 100644
--- a/tests/ui/lint/fn_must_use.stderr
+++ b/tests/ui/lint/fn_must_use.stderr
@@ -10,12 +10,21 @@ note: the lint level is defined here
    |
 LL | #![warn(unused_must_use)]
    |         ^^^^^^^^^^^^^^^
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = need_to_use_this_value();
+   |     +++++++
 
 warning: unused return value of `MyStruct::need_to_use_this_method_value` that must be used
   --> $DIR/fn_must_use.rs:60:5
    |
 LL |     m.need_to_use_this_method_value();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = m.need_to_use_this_method_value();
+   |     +++++++
 
 warning: unused return value of `EvenNature::is_even` that must be used
   --> $DIR/fn_must_use.rs:61:5
@@ -24,24 +33,43 @@ LL |     m.is_even(); // trait method!
    |     ^^^^^^^^^^^
    |
    = note: no side effects
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = m.is_even(); // trait method!
+   |     +++++++
 
 warning: unused return value of `MyStruct::need_to_use_this_associated_function_value` that must be used
   --> $DIR/fn_must_use.rs:64:5
    |
 LL |     MyStruct::need_to_use_this_associated_function_value();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = MyStruct::need_to_use_this_associated_function_value();
+   |     +++++++
 
 warning: unused return value of `std::cmp::PartialEq::eq` that must be used
   --> $DIR/fn_must_use.rs:70:5
    |
 LL |     2.eq(&3);
    |     ^^^^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = 2.eq(&3);
+   |     +++++++
 
 warning: unused return value of `std::cmp::PartialEq::eq` that must be used
   --> $DIR/fn_must_use.rs:71:5
    |
 LL |     m.eq(&n);
    |     ^^^^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = m.eq(&n);
+   |     +++++++
 
 warning: unused comparison that must be used
   --> $DIR/fn_must_use.rs:74:5
diff --git a/tests/ui/lint/issue-109152.rs b/tests/ui/lint/issue-109152.rs
new file mode 100644
index 00000000000..daf530e6d0b
--- /dev/null
+++ b/tests/ui/lint/issue-109152.rs
@@ -0,0 +1,7 @@
+#![deny(map_unit_fn)]
+
+#![crate_type = "lib"]
+fn _y() {
+    vec![42].iter().map(drop);
+    //~^ ERROR `Iterator::map` call that discard the iterator's values
+}
diff --git a/tests/ui/lint/issue-109152.stderr b/tests/ui/lint/issue-109152.stderr
new file mode 100644
index 00000000000..7db9e71a584
--- /dev/null
+++ b/tests/ui/lint/issue-109152.stderr
@@ -0,0 +1,23 @@
+error: `Iterator::map` call that discard the iterator's values
+  --> $DIR/issue-109152.rs:5:21
+   |
+LL |     vec![42].iter().map(drop);
+   |                     ^^^^----^
+   |                     |   |
+   |                     |   this function returns `()`, which is likely not what you wanted
+   |                     |   called `Iterator::map` with callable that returns `()`
+   |                     after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
+   |
+   = note: `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
+note: the lint level is defined here
+  --> $DIR/issue-109152.rs:1:9
+   |
+LL | #![deny(map_unit_fn)]
+   |         ^^^^^^^^^^^
+help: you might have meant to use `Iterator::for_each`
+   |
+LL |     vec![42].iter().for_each(drop);
+   |                     ~~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/unused/must-use-box-from-raw.stderr b/tests/ui/lint/unused/must-use-box-from-raw.stderr
index 47ab613bec2..4898db7fe3d 100644
--- a/tests/ui/lint/unused/must-use-box-from-raw.stderr
+++ b/tests/ui/lint/unused/must-use-box-from-raw.stderr
@@ -10,6 +10,10 @@ note: the lint level is defined here
    |
 LL | #![warn(unused_must_use)]
    |         ^^^^^^^^^^^^^^^
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = Box::from_raw(ptr);
+   |     +++++++
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/lint/unused/must_use-unit.stderr b/tests/ui/lint/unused/must_use-unit.stderr
index 9fcbc5074ea..993a19e5f04 100644
--- a/tests/ui/lint/unused/must_use-unit.stderr
+++ b/tests/ui/lint/unused/must_use-unit.stderr
@@ -9,12 +9,21 @@ note: the lint level is defined here
    |
 LL | #![deny(unused_must_use)]
    |         ^^^^^^^^^^^^^^^
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = foo();
+   |     +++++++
 
 error: unused return value of `bar` that must be used
   --> $DIR/must_use-unit.rs:15:5
    |
 LL |     bar();
    |     ^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = bar();
+   |     +++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lint/unused/unused-async.stderr b/tests/ui/lint/unused/unused-async.stderr
index 4bcb26dc165..1c3702ba265 100644
--- a/tests/ui/lint/unused/unused-async.stderr
+++ b/tests/ui/lint/unused/unused-async.stderr
@@ -16,12 +16,22 @@ error: unused return value of `foo` that must be used
    |
 LL |     foo();
    |     ^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = foo();
+   |     +++++++
 
 error: unused output of future returned by `foo` that must be used
   --> $DIR/unused-async.rs:33:5
    |
 LL |     foo().await;
    |     ^^^^^^^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = foo().await;
+   |     +++++++
 
 error: unused implementer of `Future` that must be used
   --> $DIR/unused-async.rs:34:5
@@ -36,12 +46,22 @@ error: unused return value of `bar` that must be used
    |
 LL |     bar();
    |     ^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = bar();
+   |     +++++++
 
 error: unused output of future returned by `bar` that must be used
   --> $DIR/unused-async.rs:36:5
    |
 LL |     bar().await;
    |     ^^^^^^^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = bar().await;
+   |     +++++++
 
 error: unused implementer of `Future` that must be used
   --> $DIR/unused-async.rs:37:5
diff --git a/tests/ui/lint/unused/unused-result.stderr b/tests/ui/lint/unused/unused-result.stderr
index 4e1ba1fd959..f42995a65d1 100644
--- a/tests/ui/lint/unused/unused-result.stderr
+++ b/tests/ui/lint/unused/unused-result.stderr
@@ -9,6 +9,10 @@ note: the lint level is defined here
    |
 LL | #![deny(unused_results, unused_must_use)]
    |                         ^^^^^^^^^^^^^^^
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = foo::<MustUse>();
+   |     +++++++
 
 error: unused `MustUseMsg` that must be used
   --> $DIR/unused-result.rs:22:5
@@ -17,6 +21,10 @@ LL |     foo::<MustUseMsg>();
    |     ^^^^^^^^^^^^^^^^^^^
    |
    = note: some message
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = foo::<MustUseMsg>();
+   |     +++++++
 
 error: unused result of type `isize`
   --> $DIR/unused-result.rs:34:5
@@ -35,6 +43,11 @@ error: unused `MustUse` that must be used
    |
 LL |     foo::<MustUse>();
    |     ^^^^^^^^^^^^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = foo::<MustUse>();
+   |     +++++++
 
 error: unused `MustUseMsg` that must be used
   --> $DIR/unused-result.rs:36:5
@@ -43,6 +56,10 @@ LL |     foo::<MustUseMsg>();
    |     ^^^^^^^^^^^^^^^^^^^
    |
    = note: some message
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = foo::<MustUseMsg>();
+   |     +++++++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr
index 0f699429e02..9633767c442 100644
--- a/tests/ui/lint/unused/unused_attributes-must_use.stderr
+++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr
@@ -146,42 +146,76 @@ note: the lint level is defined here
    |
 LL | #![deny(unused_attributes, unused_must_use)]
    |                            ^^^^^^^^^^^^^^^
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = X;
+   |     +++++++
 
 error: unused `Y` that must be used
   --> $DIR/unused_attributes-must_use.rs:104:5
    |
 LL |     Y::Z;
    |     ^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = Y::Z;
+   |     +++++++
 
 error: unused `U` that must be used
   --> $DIR/unused_attributes-must_use.rs:105:5
    |
 LL |     U { unit: () };
    |     ^^^^^^^^^^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = U { unit: () };
+   |     +++++++
 
 error: unused return value of `U::method` that must be used
   --> $DIR/unused_attributes-must_use.rs:106:5
    |
 LL |     U::method();
    |     ^^^^^^^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = U::method();
+   |     +++++++
 
 error: unused return value of `foo` that must be used
   --> $DIR/unused_attributes-must_use.rs:107:5
    |
 LL |     foo();
    |     ^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = foo();
+   |     +++++++
 
 error: unused return value of `foreign_foo` that must be used
   --> $DIR/unused_attributes-must_use.rs:110:9
    |
 LL |         foreign_foo();
    |         ^^^^^^^^^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |         let _ = foreign_foo();
+   |         +++++++
 
 error: unused return value of `Use::get_four` that must be used
   --> $DIR/unused_attributes-must_use.rs:118:5
    |
 LL |     ().get_four();
    |     ^^^^^^^^^^^^^
+   |
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = ().get_four();
+   |     +++++++
 
 error: aborting due to 28 previous errors
 
diff --git a/tests/ui/macros/issue-109237.rs b/tests/ui/macros/issue-109237.rs
new file mode 100644
index 00000000000..86a193c9e44
--- /dev/null
+++ b/tests/ui/macros/issue-109237.rs
@@ -0,0 +1,7 @@
+macro_rules! statement {
+    () => {;}; //~ ERROR expected expression
+}
+
+fn main() {
+    let _ = statement!();
+}
diff --git a/tests/ui/macros/issue-109237.stderr b/tests/ui/macros/issue-109237.stderr
new file mode 100644
index 00000000000..d125cff63ea
--- /dev/null
+++ b/tests/ui/macros/issue-109237.stderr
@@ -0,0 +1,18 @@
+error: expected expression, found `;`
+  --> $DIR/issue-109237.rs:2:12
+   |
+LL |     () => {;};
+   |            ^ expected expression
+...
+LL |     let _ = statement!();
+   |             ------------ in this macro invocation
+   |
+   = note: the macro call doesn't expand to an expression, but it can expand to a statement
+   = note: this error originates in the macro `statement` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: surround the macro invocation with `{}` to interpret the expansion as a statement
+   |
+LL |     let _ = { statement!(); };
+   |             ~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/nested-use-as.rs b/tests/ui/macros/nested-use-as.rs
new file mode 100644
index 00000000000..21aa81e8092
--- /dev/null
+++ b/tests/ui/macros/nested-use-as.rs
@@ -0,0 +1,83 @@
+// check-pass
+// edition:2018
+// issue: https://github.com/rust-lang/rust/issues/97534
+
+macro_rules! m {
+    () => {
+        macro_rules! foo {
+            () => {}
+        }
+        use foo as bar;
+    }
+}
+
+m!{}
+
+use bar as baz;
+
+baz!{}
+
+macro_rules! foo2 {
+    () => {};
+}
+
+macro_rules! m2 {
+    () => {
+        use foo2 as bar2;
+    };
+}
+
+m2! {}
+
+use bar2 as baz2;
+
+baz2! {}
+
+macro_rules! n1 {
+    () => {
+        macro_rules! n2 {
+            () => {
+                macro_rules! n3 {
+                    () => {
+                        macro_rules! n4 {
+                            () => {}
+                        }
+                        use n4 as c4;
+                    }
+                }
+                use n3 as c3;
+            }
+        }
+        use n2 as c2;
+    }
+}
+
+use n1 as c1;
+c1!{}
+use c2 as a2;
+a2!{}
+use c3 as a3;
+a3!{}
+use c4 as a4;
+a4!{}
+
+// https://github.com/rust-lang/rust/pull/108729#issuecomment-1474750675
+// reversed
+use d5 as d6;
+use d4 as d5;
+use d3 as d4;
+use d2 as d3;
+use d1 as d2;
+use foo2 as d1;
+d6! {}
+
+// mess
+use f3 as f4;
+f5! {}
+use f1 as f2;
+use f4 as f5;
+use f2 as f3;
+use foo2 as f1;
+
+fn main() {
+}
diff --git a/tests/ui/methods/method-call-lifetime-args-fail.stderr b/tests/ui/methods/method-call-lifetime-args-fail.stderr
index 34526256f99..645d8b8d14a 100644
--- a/tests/ui/methods/method-call-lifetime-args-fail.stderr
+++ b/tests/ui/methods/method-call-lifetime-args-fail.stderr
@@ -30,7 +30,7 @@ note: method defined here, with 2 lifetime parameters: `'a`, `'b`
 LL |     fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} }
    |        ^^^^^ --  --
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:27:15
    |
 LL |     S::late::<'static>(S, &0, &0);
@@ -42,7 +42,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
    |             ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:29:15
    |
 LL |     S::late::<'static, 'static>(S, &0, &0);
@@ -54,7 +54,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
    |             ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:31:15
    |
 LL |     S::late::<'static, 'static, 'static>(S, &0, &0);
@@ -66,7 +66,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
    |             ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:34:21
    |
 LL |     S::late_early::<'static, 'static>(S, &0);
@@ -78,7 +78,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} }
    |                   ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:36:21
    |
 LL |     S::late_early::<'static, 'static, 'static>(S, &0);
@@ -90,7 +90,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} }
    |                   ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:40:24
    |
 LL |     S::late_implicit::<'static>(S, &0, &0);
@@ -102,7 +102,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late_implicit(self, _: &u8, _: &u8) {}
    |                               ^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:42:24
    |
 LL |     S::late_implicit::<'static, 'static>(S, &0, &0);
@@ -114,7 +114,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late_implicit(self, _: &u8, _: &u8) {}
    |                               ^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:44:24
    |
 LL |     S::late_implicit::<'static, 'static, 'static>(S, &0, &0);
@@ -126,7 +126,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late_implicit(self, _: &u8, _: &u8) {}
    |                               ^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:47:30
    |
 LL |     S::late_implicit_early::<'static, 'static>(S, &0);
@@ -138,7 +138,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} }
    |                                         ^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:49:30
    |
 LL |     S::late_implicit_early::<'static, 'static, 'static>(S, &0);
@@ -150,7 +150,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} }
    |                                         ^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:52:35
    |
 LL |     S::late_implicit_self_early::<'static, 'static>(&S);
@@ -162,7 +162,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} }
    |                                     ^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:54:35
    |
 LL |     S::late_implicit_self_early::<'static, 'static, 'static>(&S);
@@ -174,7 +174,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} }
    |                                     ^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:57:28
    |
 LL |     S::late_unused_early::<'static, 'static>(S);
@@ -186,7 +186,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} }
    |                          ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args-fail.rs:59:28
    |
 LL |     S::late_unused_early::<'static, 'static, 'static>(S);
@@ -232,4 +232,5 @@ LL |     fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} }
 
 error: aborting due to 18 previous errors
 
-For more information about this error, try `rustc --explain E0107`.
+Some errors have detailed explanations: E0107, E0794.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/methods/method-call-lifetime-args.stderr b/tests/ui/methods/method-call-lifetime-args.stderr
index 64ae79e9bb2..b215d583217 100644
--- a/tests/ui/methods/method-call-lifetime-args.stderr
+++ b/tests/ui/methods/method-call-lifetime-args.stderr
@@ -1,4 +1,4 @@
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args.rs:9:15
    |
 LL |     S::late::<'static>(S, &0, &0);
@@ -10,7 +10,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
    |             ^^
 
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/method-call-lifetime-args.rs:11:24
    |
 LL |     S::late_implicit::<'static>(S, &0, &0);
@@ -24,3 +24,4 @@ LL |     fn late_implicit(self, _: &u8, _: &u8) {}
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0794`.
diff --git a/tests/ui/panic-runtime/unwind-tables-target-required.rs b/tests/ui/panic-runtime/unwind-tables-target-required.rs
index 3abb52b675a..5a90b314a6e 100644
--- a/tests/ui/panic-runtime/unwind-tables-target-required.rs
+++ b/tests/ui/panic-runtime/unwind-tables-target-required.rs
@@ -1,10 +1,11 @@
 // Tests that the compiler errors if the user tries to turn off unwind tables
 // when they are required.
 //
-// only-x86_64-windows-msvc
+// only-x86_64-pc-windows-msvc
 // compile-flags: -C force-unwind-tables=no
 //
-// error-pattern: target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`.
+// dont-check-compiler-stderr
+// error-pattern: target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`
 
 pub fn main() {
 }
diff --git a/tests/ui/parser/fn-header-semantic-fail.rs b/tests/ui/parser/fn-header-semantic-fail.rs
index cf5d3dab4aa..71f18a27e7c 100644
--- a/tests/ui/parser/fn-header-semantic-fail.rs
+++ b/tests/ui/parser/fn-header-semantic-fail.rs
@@ -11,7 +11,6 @@ fn main() {
     extern "C" fn ff4() {} // OK.
     const async unsafe extern "C" fn ff5() {}
     //~^ ERROR functions cannot be both `const` and `async`
-    //~| ERROR cycle detected
 
     trait X {
         async fn ft1(); //~ ERROR functions in traits cannot be declared `async`
@@ -34,7 +33,6 @@ fn main() {
         //~^ ERROR functions in traits cannot be declared `async`
         //~| ERROR functions in traits cannot be declared const
         //~| ERROR functions cannot be both `const` and `async`
-        //~| ERROR cycle detected
     }
 
     impl Y {
@@ -44,7 +42,6 @@ fn main() {
         extern "C" fn fi4() {} // OK.
         const async unsafe extern "C" fn fi5() {}
         //~^ ERROR functions cannot be both `const` and `async`
-        //~| ERROR cycle detected
     }
 
     extern "C" {
diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr
index 2d8bd19a731..7f7b7e835f8 100644
--- a/tests/ui/parser/fn-header-semantic-fail.stderr
+++ b/tests/ui/parser/fn-header-semantic-fail.stderr
@@ -8,19 +8,19 @@ LL |     const async unsafe extern "C" fn ff5() {}
    |     `const` because of this
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:19:9
+  --> $DIR/fn-header-semantic-fail.rs:18:9
    |
 LL |         const fn ft3();
    |         ^^^^^ functions in traits cannot be const
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:21:9
+  --> $DIR/fn-header-semantic-fail.rs:20:9
    |
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^ functions in traits cannot be const
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:21:9
+  --> $DIR/fn-header-semantic-fail.rs:20:9
    |
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^-^^^^^----------------------------
@@ -29,19 +29,19 @@ LL |         const async unsafe extern "C" fn ft5();
    |         `const` because of this
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:31:9
+  --> $DIR/fn-header-semantic-fail.rs:30:9
    |
 LL |         const fn ft3() {}
    |         ^^^^^ functions in traits cannot be const
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:33:9
+  --> $DIR/fn-header-semantic-fail.rs:32:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^ functions in traits cannot be const
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:33:9
+  --> $DIR/fn-header-semantic-fail.rs:32:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^-^^^^^------------------------------
@@ -50,7 +50,7 @@ LL |         const async unsafe extern "C" fn ft5() {}
    |         `const` because of this
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:45:9
+  --> $DIR/fn-header-semantic-fail.rs:43:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^-^^^^^------------------------------
@@ -59,7 +59,7 @@ LL |         const async unsafe extern "C" fn fi5() {}
    |         `const` because of this
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:51:18
+  --> $DIR/fn-header-semantic-fail.rs:48:18
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -72,7 +72,7 @@ LL |         fn fe1();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:52:19
+  --> $DIR/fn-header-semantic-fail.rs:49:19
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -86,7 +86,7 @@ LL |         fn fe2();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:53:18
+  --> $DIR/fn-header-semantic-fail.rs:50:18
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -100,7 +100,7 @@ LL |         fn fe3();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:54:23
+  --> $DIR/fn-header-semantic-fail.rs:51:23
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -114,7 +114,7 @@ LL |         fn fe4();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:55:42
+  --> $DIR/fn-header-semantic-fail.rs:52:42
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -128,7 +128,7 @@ LL |         fn fe5();
    |         ~~
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:55:9
+  --> $DIR/fn-header-semantic-fail.rs:52:9
    |
 LL |         const async unsafe extern "C" fn fe5();
    |         ^^^^^-^^^^^----------------------------
@@ -137,7 +137,7 @@ LL |         const async unsafe extern "C" fn fe5();
    |         `const` because of this
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:17:9
+  --> $DIR/fn-header-semantic-fail.rs:16:9
    |
 LL |         async fn ft1();
    |         -----^^^^^^^^^^
@@ -150,7 +150,7 @@ LL |         async fn ft1();
    = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:21:9
+  --> $DIR/fn-header-semantic-fail.rs:20:9
    |
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +163,7 @@ LL |         const async unsafe extern "C" fn ft5();
    = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:29:9
+  --> $DIR/fn-header-semantic-fail.rs:28:9
    |
 LL |         async fn ft1() {}
    |         -----^^^^^^^^^
@@ -176,7 +176,7 @@ LL |         async fn ft1() {}
    = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:33:9
+  --> $DIR/fn-header-semantic-fail.rs:32:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -188,115 +188,7 @@ LL |         const async unsafe extern "C" fn ft5() {}
    = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
    = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
 
-error[E0391]: cycle detected when computing type of `main::ff5::{opaque#0}`
-  --> $DIR/fn-header-semantic-fail.rs:12:44
-   |
-LL |     const async unsafe extern "C" fn ff5() {}
-   |                                            ^
-   |
-note: ...which requires borrow-checking `main::ff5`...
-  --> $DIR/fn-header-semantic-fail.rs:12:5
-   |
-LL |     const async unsafe extern "C" fn ff5() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing MIR for `main::ff5`...
-  --> $DIR/fn-header-semantic-fail.rs:12:5
-   |
-LL |     const async unsafe extern "C" fn ff5() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const checking `main::ff5`...
-  --> $DIR/fn-header-semantic-fail.rs:12:5
-   |
-LL |     const async unsafe extern "C" fn ff5() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing whether `main::ff5::{opaque#0}` is freeze...
-   = note: ...which requires evaluating trait selection obligation `main::ff5::{opaque#0}: core::marker::Freeze`...
-   = note: ...which again requires computing type of `main::ff5::{opaque#0}`, completing the cycle
-note: cycle used when checking item types in top-level module
-  --> $DIR/fn-header-semantic-fail.rs:5:1
-   |
-LL | / #![feature(const_extern_fn)]
-LL | |
-LL | | fn main() {
-LL | |     async fn ff1() {} // OK.
-...  |
-LL | |     }
-LL | | }
-   | |_^
-
-error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}`
-  --> $DIR/fn-header-semantic-fail.rs:33:48
-   |
-LL |         const async unsafe extern "C" fn ft5() {}
-   |                                                ^
-   |
-note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5`...
-  --> $DIR/fn-header-semantic-fail.rs:33:9
-   |
-LL |         const async unsafe extern "C" fn ft5() {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing MIR for `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5`...
-  --> $DIR/fn-header-semantic-fail.rs:33:9
-   |
-LL |         const async unsafe extern "C" fn ft5() {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5`...
-  --> $DIR/fn-header-semantic-fail.rs:33:9
-   |
-LL |         const async unsafe extern "C" fn ft5() {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing whether `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}` is freeze...
-   = note: ...which requires evaluating trait selection obligation `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}: core::marker::Freeze`...
-   = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}`, completing the cycle
-note: cycle used when checking item types in top-level module
-  --> $DIR/fn-header-semantic-fail.rs:5:1
-   |
-LL | / #![feature(const_extern_fn)]
-LL | |
-LL | | fn main() {
-LL | |     async fn ff1() {} // OK.
-...  |
-LL | |     }
-LL | | }
-   | |_^
-
-error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}`
-  --> $DIR/fn-header-semantic-fail.rs:45:48
-   |
-LL |         const async unsafe extern "C" fn fi5() {}
-   |                                                ^
-   |
-note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5`...
-  --> $DIR/fn-header-semantic-fail.rs:45:9
-   |
-LL |         const async unsafe extern "C" fn fi5() {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing MIR for `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5`...
-  --> $DIR/fn-header-semantic-fail.rs:45:9
-   |
-LL |         const async unsafe extern "C" fn fi5() {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5`...
-  --> $DIR/fn-header-semantic-fail.rs:45:9
-   |
-LL |         const async unsafe extern "C" fn fi5() {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing whether `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}` is freeze...
-   = note: ...which requires evaluating trait selection obligation `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}: core::marker::Freeze`...
-   = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}`, completing the cycle
-note: cycle used when checking item types in top-level module
-  --> $DIR/fn-header-semantic-fail.rs:5:1
-   |
-LL | / #![feature(const_extern_fn)]
-LL | |
-LL | | fn main() {
-LL | |     async fn ff1() {} // OK.
-...  |
-LL | |     }
-LL | | }
-   | |_^
-
-error: aborting due to 21 previous errors
+error: aborting due to 18 previous errors
 
-Some errors have detailed explanations: E0379, E0391, E0706.
+Some errors have detailed explanations: E0379, E0706.
 For more information about an error, try `rustc --explain E0379`.
diff --git a/tests/ui/pattern/issue-106862.fixed b/tests/ui/pattern/issue-106862.fixed
new file mode 100644
index 00000000000..9b27a61ffd0
--- /dev/null
+++ b/tests/ui/pattern/issue-106862.fixed
@@ -0,0 +1,44 @@
+// run-rustfix
+
+#![allow(unused)]
+
+use Foo::{FooB, FooA};
+
+enum Foo {
+    FooA { opt_x: Option<i32>, y: i32 },
+    FooB { x: i32, y: i32 }
+}
+
+fn main() {
+    let f = FooB { x: 3, y: 4 };
+
+    match f {
+        FooB { x: a, y: b } => println!("{} {}", a, b),
+        //~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
+        _ => (),
+    }
+
+    match f {
+        FooB { x, y } => println!("{} {}", x, y),
+        //~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
+        _ => (),
+    }
+
+    match f {
+        FooA { opt_x: Some(x), y } => println!("{} {}", x, y),
+        //~^ ERROR expected tuple struct or tuple variant, found variant `FooA`
+        _ => (),
+    }
+
+    match f {
+        FooB { x: a, y: _ } => println!("{}", a),
+        //~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
+        _ => (),
+    }
+
+    match f {
+        FooB { x, y } => (),
+        //~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
+        _ => (),
+    }
+}
diff --git a/tests/ui/pattern/issue-106862.rs b/tests/ui/pattern/issue-106862.rs
new file mode 100644
index 00000000000..590430a7843
--- /dev/null
+++ b/tests/ui/pattern/issue-106862.rs
@@ -0,0 +1,44 @@
+// run-rustfix
+
+#![allow(unused)]
+
+use Foo::{FooB, FooA};
+
+enum Foo {
+    FooA { opt_x: Option<i32>, y: i32 },
+    FooB { x: i32, y: i32 }
+}
+
+fn main() {
+    let f = FooB { x: 3, y: 4 };
+
+    match f {
+        FooB(a, b) => println!("{} {}", a, b),
+        //~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
+        _ => (),
+    }
+
+    match f {
+        FooB(x, y) => println!("{} {}", x, y),
+        //~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
+        _ => (),
+    }
+
+    match f {
+        FooA(Some(x), y) => println!("{} {}", x, y),
+        //~^ ERROR expected tuple struct or tuple variant, found variant `FooA`
+        _ => (),
+    }
+
+    match f {
+        FooB(a, _, _) => println!("{}", a),
+        //~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
+        _ => (),
+    }
+
+    match f {
+        FooB() => (),
+        //~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
+        _ => (),
+    }
+}
diff --git a/tests/ui/pattern/issue-106862.stderr b/tests/ui/pattern/issue-106862.stderr
new file mode 100644
index 00000000000..27f8ac97284
--- /dev/null
+++ b/tests/ui/pattern/issue-106862.stderr
@@ -0,0 +1,48 @@
+error[E0532]: expected tuple struct or tuple variant, found variant `FooB`
+  --> $DIR/issue-106862.rs:16:9
+   |
+LL |     FooB { x: i32, y: i32 }
+   |     ----------------------- `FooB` defined here
+...
+LL |         FooB(a, b) => println!("{} {}", a, b),
+   |         ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x: a, y: b }`
+
+error[E0532]: expected tuple struct or tuple variant, found variant `FooB`
+  --> $DIR/issue-106862.rs:22:9
+   |
+LL |     FooB { x: i32, y: i32 }
+   |     ----------------------- `FooB` defined here
+...
+LL |         FooB(x, y) => println!("{} {}", x, y),
+   |         ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }`
+
+error[E0532]: expected tuple struct or tuple variant, found variant `FooA`
+  --> $DIR/issue-106862.rs:28:9
+   |
+LL |     FooA { opt_x: Option<i32>, y: i32 },
+   |     ----------------------------------- `FooA` defined here
+...
+LL |         FooA(Some(x), y) => println!("{} {}", x, y),
+   |         ^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FooA { opt_x: Some(x), y }`
+
+error[E0532]: expected tuple struct or tuple variant, found variant `FooB`
+  --> $DIR/issue-106862.rs:34:9
+   |
+LL |     FooB { x: i32, y: i32 }
+   |     ----------------------- `FooB` defined here
+...
+LL |         FooB(a, _, _) => println!("{}", a),
+   |         ^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x: a, y: _ }`
+
+error[E0532]: expected tuple struct or tuple variant, found variant `FooB`
+  --> $DIR/issue-106862.rs:40:9
+   |
+LL |     FooB { x: i32, y: i32 }
+   |     ----------------------- `FooB` defined here
+...
+LL |         FooB() => (),
+   |         ^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0532`.
diff --git a/tests/ui/proc-macro/bad-projection.rs b/tests/ui/proc-macro/bad-projection.rs
new file mode 100644
index 00000000000..d214c7ac8b2
--- /dev/null
+++ b/tests/ui/proc-macro/bad-projection.rs
@@ -0,0 +1,15 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![allow(warnings)]
+
+extern crate proc_macro;
+
+trait Project {
+    type Assoc;
+}
+
+#[proc_macro]
+pub fn uwu() -> <() as Project>::Assoc {}
+//~^ ERROR the trait bound `(): Project` is not satisfied
diff --git a/tests/ui/proc-macro/bad-projection.stderr b/tests/ui/proc-macro/bad-projection.stderr
new file mode 100644
index 00000000000..8a8246376fe
--- /dev/null
+++ b/tests/ui/proc-macro/bad-projection.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `(): Project` is not satisfied
+  --> $DIR/bad-projection.rs:14:17
+   |
+LL | pub fn uwu() -> <() as Project>::Assoc {}
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ the trait `Project` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/proc-macro/proc-macro-abi.rs b/tests/ui/proc-macro/proc-macro-abi.rs
index 873660a5b3a..93a613e8b8f 100644
--- a/tests/ui/proc-macro/proc-macro-abi.rs
+++ b/tests/ui/proc-macro/proc-macro-abi.rs
@@ -9,19 +9,19 @@ use proc_macro::TokenStream;
 
 #[proc_macro]
 pub extern "C" fn abi(a: TokenStream) -> TokenStream {
-    //~^ ERROR proc macro functions may not be `extern "C"`
+    //~^ ERROR function-like proc macro has incorrect signature
     a
 }
 
 #[proc_macro]
 pub extern "system" fn abi2(a: TokenStream) -> TokenStream {
-    //~^ ERROR proc macro functions may not be `extern "system"`
+    //~^ ERROR function-like proc macro has incorrect signature
     a
 }
 
 #[proc_macro]
 pub extern fn abi3(a: TokenStream) -> TokenStream {
-    //~^ ERROR proc macro functions may not be `extern "C"`
+    //~^ ERROR function-like proc macro has incorrect signature
     a
 }
 
diff --git a/tests/ui/proc-macro/proc-macro-abi.stderr b/tests/ui/proc-macro/proc-macro-abi.stderr
index 9a781be0996..ccc72e5187e 100644
--- a/tests/ui/proc-macro/proc-macro-abi.stderr
+++ b/tests/ui/proc-macro/proc-macro-abi.stderr
@@ -1,20 +1,29 @@
-error: proc macro functions may not be `extern "C"`
+error: function-like proc macro has incorrect signature
   --> $DIR/proc-macro-abi.rs:11:1
    |
 LL | pub extern "C" fn abi(a: TokenStream) -> TokenStream {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "Rust" fn, found "C" fn
+   |
+   = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `extern "C" fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
 
-error: proc macro functions may not be `extern "system"`
+error: function-like proc macro has incorrect signature
   --> $DIR/proc-macro-abi.rs:17:1
    |
 LL | pub extern "system" fn abi2(a: TokenStream) -> TokenStream {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "Rust" fn, found "system" fn
+   |
+   = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `extern "system" fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
 
-error: proc macro functions may not be `extern "C"`
+error: function-like proc macro has incorrect signature
   --> $DIR/proc-macro-abi.rs:23:1
    |
 LL | pub extern fn abi3(a: TokenStream) -> TokenStream {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "Rust" fn, found "C" fn
+   |
+   = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `extern "C" fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/proc-macro/signature-proc-macro-attribute.rs b/tests/ui/proc-macro/signature-proc-macro-attribute.rs
index 51abc8e7d3e..fb48f748ce0 100644
--- a/tests/ui/proc-macro/signature-proc-macro-attribute.rs
+++ b/tests/ui/proc-macro/signature-proc-macro-attribute.rs
@@ -8,25 +8,23 @@ use proc_macro::TokenStream;
 
 #[proc_macro_attribute]
 pub fn bad_input(input: String) -> TokenStream {
-    //~^ ERROR mismatched attribute proc macro signature
+    //~^ ERROR attribute proc macro has incorrect signature
     ::proc_macro::TokenStream::new()
 }
 
 #[proc_macro_attribute]
 pub fn bad_output(input: TokenStream) -> String {
-    //~^ ERROR mismatched attribute proc macro signature
-    //~| ERROR mismatched attribute proc macro signature
+    //~^ ERROR attribute proc macro has incorrect signature
     String::from("blah")
 }
 
 #[proc_macro_attribute]
 pub fn bad_everything(input: String) -> String {
-    //~^ ERROR mismatched attribute proc macro signature
-    //~| ERROR mismatched attribute proc macro signature
+    //~^ ERROR attribute proc macro has incorrect signature
     input
 }
 
 #[proc_macro_attribute]
 pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
-    //~^ ERROR mismatched attribute proc macro signature
+    //~^ ERROR attribute proc macro has incorrect signature
 }
diff --git a/tests/ui/proc-macro/signature-proc-macro-attribute.stderr b/tests/ui/proc-macro/signature-proc-macro-attribute.stderr
index abf7a6f3ce9..ce832eaa5c7 100644
--- a/tests/ui/proc-macro/signature-proc-macro-attribute.stderr
+++ b/tests/ui/proc-macro/signature-proc-macro-attribute.stderr
@@ -1,42 +1,38 @@
-error: mismatched attribute proc macro signature
+error: attribute proc macro has incorrect signature
   --> $DIR/signature-proc-macro-attribute.rs:10:1
    |
 LL | pub fn bad_input(input: String) -> TokenStream {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream`
-
-error: mismatched attribute proc macro signature
-  --> $DIR/signature-proc-macro-attribute.rs:16:42
-   |
-LL | pub fn bad_output(input: TokenStream) -> String {
-   |                                          ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-   = note: attribute proc macros must have a signature of `fn(TokenStream, TokenStream) -> TokenStream`
+   = note: expected signature `fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `fn(std::string::String) -> proc_macro::TokenStream`
 
-error: mismatched attribute proc macro signature
+error: attribute proc macro has incorrect signature
   --> $DIR/signature-proc-macro-attribute.rs:16:1
    |
 LL | pub fn bad_output(input: TokenStream) -> String {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream`
-
-error: mismatched attribute proc macro signature
-  --> $DIR/signature-proc-macro-attribute.rs:23:41
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-LL | pub fn bad_everything(input: String) -> String {
-   |                                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
-   |
-   = note: attribute proc macros must have a signature of `fn(TokenStream, TokenStream) -> TokenStream`
+   = note: expected signature `fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `fn(proc_macro::TokenStream) -> std::string::String`
 
-error: mismatched attribute proc macro signature
-  --> $DIR/signature-proc-macro-attribute.rs:23:1
+error: attribute proc macro has incorrect signature
+  --> $DIR/signature-proc-macro-attribute.rs:22:1
    |
 LL | pub fn bad_everything(input: String) -> String {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
+   |
+   = note: expected signature `fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `fn(std::string::String) -> std::string::String`
 
-error: mismatched attribute proc macro signature
-  --> $DIR/signature-proc-macro-attribute.rs:30:49
+error: attribute proc macro has incorrect signature
+  --> $DIR/signature-proc-macro-attribute.rs:28:52
    |
 LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
-   |                                                 ^^^^^^^^^ found unexpected argument
+   |                                                    ^^^^^^ incorrect number of function parameters
+   |
+   = note: expected signature `fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `fn(proc_macro::TokenStream, proc_macro::TokenStream, std::string::String) -> proc_macro::TokenStream`
 
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/proc-macro/signature-proc-macro-derive.rs b/tests/ui/proc-macro/signature-proc-macro-derive.rs
index f2fd824b675..d294b159127 100644
--- a/tests/ui/proc-macro/signature-proc-macro-derive.rs
+++ b/tests/ui/proc-macro/signature-proc-macro-derive.rs
@@ -8,24 +8,23 @@ use proc_macro::TokenStream;
 
 #[proc_macro_derive(Blah)]
 pub fn bad_input(input: String) -> TokenStream {
-    //~^ ERROR mismatched derive proc macro signature
+    //~^ ERROR derive proc macro has incorrect signature
     TokenStream::new()
 }
 
 #[proc_macro_derive(Bleh)]
 pub fn bad_output(input: TokenStream) -> String {
-    //~^ ERROR mismatched derive proc macro signature
+    //~^ ERROR derive proc macro has incorrect signature
     String::from("blah")
 }
 
 #[proc_macro_derive(Bluh)]
 pub fn bad_everything(input: String) -> String {
-    //~^ ERROR mismatched derive proc macro signature
-    //~| ERROR mismatched derive proc macro signature
+    //~^ ERROR derive proc macro has incorrect signature
     input
 }
 
 #[proc_macro_derive(Blih)]
 pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
-    //~^ ERROR mismatched derive proc macro signature
+    //~^ ERROR derive proc macro has incorrect signature
 }
diff --git a/tests/ui/proc-macro/signature-proc-macro-derive.stderr b/tests/ui/proc-macro/signature-proc-macro-derive.stderr
index a358ae27703..03c6abad17d 100644
--- a/tests/ui/proc-macro/signature-proc-macro-derive.stderr
+++ b/tests/ui/proc-macro/signature-proc-macro-derive.stderr
@@ -1,40 +1,38 @@
-error: mismatched derive proc macro signature
+error: derive proc macro has incorrect signature
   --> $DIR/signature-proc-macro-derive.rs:10:25
    |
 LL | pub fn bad_input(input: String) -> TokenStream {
-   |                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |                         ^^^^^^ expected `proc_macro::TokenStream`, found `std::string::String`
    |
-   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+   = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `fn(std::string::String) -> proc_macro::TokenStream`
 
-error: mismatched derive proc macro signature
+error: derive proc macro has incorrect signature
   --> $DIR/signature-proc-macro-derive.rs:16:42
    |
 LL | pub fn bad_output(input: TokenStream) -> String {
-   |                                          ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |                                          ^^^^^^ expected `proc_macro::TokenStream`, found `std::string::String`
    |
-   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+   = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `fn(proc_macro::TokenStream) -> std::string::String`
 
-error: mismatched derive proc macro signature
-  --> $DIR/signature-proc-macro-derive.rs:22:41
-   |
-LL | pub fn bad_everything(input: String) -> String {
-   |                                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
-   |
-   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
-
-error: mismatched derive proc macro signature
+error: derive proc macro has incorrect signature
   --> $DIR/signature-proc-macro-derive.rs:22:30
    |
 LL | pub fn bad_everything(input: String) -> String {
-   |                              ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |                              ^^^^^^ expected `proc_macro::TokenStream`, found `std::string::String`
    |
-   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+   = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `fn(std::string::String) -> std::string::String`
 
-error: mismatched derive proc macro signature
-  --> $DIR/signature-proc-macro-derive.rs:29:33
+error: derive proc macro has incorrect signature
+  --> $DIR/signature-proc-macro-derive.rs:28:36
    |
 LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^ found unexpected arguments
+   |                                    ^^^^^^^^^^^ incorrect number of function parameters
+   |
+   = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `fn(proc_macro::TokenStream, proc_macro::TokenStream, std::string::String) -> proc_macro::TokenStream`
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/proc-macro/signature-proc-macro.rs b/tests/ui/proc-macro/signature-proc-macro.rs
index 54770aacd1a..ca2509ed84b 100644
--- a/tests/ui/proc-macro/signature-proc-macro.rs
+++ b/tests/ui/proc-macro/signature-proc-macro.rs
@@ -8,24 +8,23 @@ use proc_macro::TokenStream;
 
 #[proc_macro]
 pub fn bad_input(input: String) -> TokenStream {
-    //~^ ERROR mismatched function-like proc macro signature
+    //~^ ERROR function-like proc macro has incorrect signature
     ::proc_macro::TokenStream::new()
 }
 
 #[proc_macro]
 pub fn bad_output(input: TokenStream) -> String {
-    //~^ ERROR mismatched function-like proc macro signature
+    //~^ ERROR function-like proc macro has incorrect signature
     String::from("blah")
 }
 
 #[proc_macro]
 pub fn bad_everything(input: String) -> String {
-    //~^ ERROR mismatched function-like proc macro signature
-    //~| ERROR mismatched function-like proc macro signature
+    //~^ ERROR function-like proc macro has incorrect signature
     input
 }
 
 #[proc_macro]
 pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
-    //~^ ERROR mismatched function-like proc macro signature
+    //~^ ERROR function-like proc macro has incorrect signature
 }
diff --git a/tests/ui/proc-macro/signature-proc-macro.stderr b/tests/ui/proc-macro/signature-proc-macro.stderr
index 4b14a54e675..dd2cb0570da 100644
--- a/tests/ui/proc-macro/signature-proc-macro.stderr
+++ b/tests/ui/proc-macro/signature-proc-macro.stderr
@@ -1,40 +1,38 @@
-error: mismatched function-like proc macro signature
+error: function-like proc macro has incorrect signature
   --> $DIR/signature-proc-macro.rs:10:25
    |
 LL | pub fn bad_input(input: String) -> TokenStream {
-   |                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |                         ^^^^^^ expected `proc_macro::TokenStream`, found `std::string::String`
    |
-   = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+   = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `fn(std::string::String) -> proc_macro::TokenStream`
 
-error: mismatched function-like proc macro signature
+error: function-like proc macro has incorrect signature
   --> $DIR/signature-proc-macro.rs:16:42
    |
 LL | pub fn bad_output(input: TokenStream) -> String {
-   |                                          ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |                                          ^^^^^^ expected `proc_macro::TokenStream`, found `std::string::String`
    |
-   = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+   = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `fn(proc_macro::TokenStream) -> std::string::String`
 
-error: mismatched function-like proc macro signature
-  --> $DIR/signature-proc-macro.rs:22:41
-   |
-LL | pub fn bad_everything(input: String) -> String {
-   |                                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
-   |
-   = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
-
-error: mismatched function-like proc macro signature
+error: function-like proc macro has incorrect signature
   --> $DIR/signature-proc-macro.rs:22:30
    |
 LL | pub fn bad_everything(input: String) -> String {
-   |                              ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |                              ^^^^^^ expected `proc_macro::TokenStream`, found `std::string::String`
    |
-   = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+   = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `fn(std::string::String) -> std::string::String`
 
-error: mismatched function-like proc macro signature
-  --> $DIR/signature-proc-macro.rs:29:33
+error: function-like proc macro has incorrect signature
+  --> $DIR/signature-proc-macro.rs:28:36
    |
 LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^ found unexpected arguments
+   |                                    ^^^^^^^^^^^ incorrect number of function parameters
+   |
+   = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `fn(proc_macro::TokenStream, proc_macro::TokenStream, std::string::String) -> proc_macro::TokenStream`
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/proc-macro/signature.rs b/tests/ui/proc-macro/signature.rs
index 11187aa31bd..7b4982a6178 100644
--- a/tests/ui/proc-macro/signature.rs
+++ b/tests/ui/proc-macro/signature.rs
@@ -8,10 +8,6 @@ extern crate proc_macro;
 
 #[proc_macro_derive(A)]
 pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
-    //~^ ERROR: mismatched derive proc macro signature
-    //~| mismatched derive proc macro signature
-    //~| mismatched derive proc macro signature
-    //~| proc macro functions may not be `extern
-    //~| proc macro functions may not be `unsafe
+    //~^ ERROR: derive proc macro has incorrect signature
     loop {}
 }
diff --git a/tests/ui/proc-macro/signature.stderr b/tests/ui/proc-macro/signature.stderr
index 3dbe3f22a0d..ba5c8c1571e 100644
--- a/tests/ui/proc-macro/signature.stderr
+++ b/tests/ui/proc-macro/signature.stderr
@@ -1,36 +1,11 @@
-error: proc macro functions may not be `extern "C"`
+error: derive proc macro has incorrect signature
   --> $DIR/signature.rs:10:1
    |
 LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: proc macro functions may not be `unsafe`
-  --> $DIR/signature.rs:10:1
-   |
-LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: mismatched derive proc macro signature
-  --> $DIR/signature.rs:10:49
-   |
-LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
-   |                                                 ^^^ found u32, expected type `proc_macro::TokenStream`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn
    |
-   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
-
-error: mismatched derive proc macro signature
-  --> $DIR/signature.rs:10:33
-   |
-LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
-   |                                 ^^^ found i32, expected type `proc_macro::TokenStream`
-   |
-   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
-
-error: mismatched derive proc macro signature
-  --> $DIR/signature.rs:10:38
-   |
-LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
-   |                                      ^^^^^^ found unexpected argument
+   = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
+              found signature `unsafe extern "C" fn(i32, u32) -> u32`
 
-error: aborting due to 5 previous errors
+error: aborting due to previous error
 
diff --git a/tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs b/tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
index 87e52881c15..23d2a4b0a99 100644
--- a/tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
+++ b/tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
@@ -1,5 +1,6 @@
 // run-pass
 // revisions: default mir-opt
+//[default] compile-flags: -Zinline-mir=no
 //[mir-opt] compile-flags: -Zmir-opt-level=4
 
 macro_rules! caller_location_from_macro {
@@ -9,13 +10,13 @@ macro_rules! caller_location_from_macro {
 fn main() {
     let loc = core::panic::Location::caller();
     assert_eq!(loc.file(), file!());
-    assert_eq!(loc.line(), 10);
+    assert_eq!(loc.line(), 11);
     assert_eq!(loc.column(), 15);
 
     // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
     // i.e. point to where the macro was invoked, instead of the macro itself.
     let loc2 = caller_location_from_macro!();
     assert_eq!(loc2.file(), file!());
-    assert_eq!(loc2.line(), 17);
+    assert_eq!(loc2.line(), 18);
     assert_eq!(loc2.column(), 16);
 }
diff --git a/tests/ui/rfc-2091-track-caller/mir-inlined-macro.rs b/tests/ui/rfc-2091-track-caller/mir-inlined-macro.rs
new file mode 100644
index 00000000000..a2e8eb27ede
--- /dev/null
+++ b/tests/ui/rfc-2091-track-caller/mir-inlined-macro.rs
@@ -0,0 +1,23 @@
+// run-pass
+// revisions: default mir-opt
+//[default] compile-flags: -Zinline-mir=no
+//[mir-opt] compile-flags: -Zmir-opt-level=4
+
+use std::panic::Location;
+
+macro_rules! f {
+    () => {
+        Location::caller()
+    };
+}
+
+#[inline(always)]
+fn g() -> &'static Location<'static> {
+    f!()
+}
+
+fn main() {
+    let loc = g();
+    assert_eq!(loc.line(), 16);
+    assert_eq!(loc.column(), 5);
+}
diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs
index 582b480aa25..5fd7c647c25 100644
--- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs
+++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs
@@ -2,11 +2,11 @@
 
 // An impl that has an erroneous const substitution should not specialize one
 // that is well-formed.
-
+#[derive(Clone)]
 struct S<const L: usize>;
 
 impl<const N: i32> Copy for S<N> {}
+//~^ ERROR the constant `N` is not of type `usize`
 impl<const M: usize> Copy for S<M> {}
-//~^ ERROR conflicting implementations of trait `Copy` for type `S<_>`
 
 fn main() {}
diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
index a3906a9a22f..6d7028c5e70 100644
--- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
+++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
@@ -1,11 +1,14 @@
-error[E0119]: conflicting implementations of trait `Copy` for type `S<_>`
-  --> $DIR/bad-const-wf-doesnt-specialize.rs:9:1
+error: the constant `N` is not of type `usize`
+  --> $DIR/bad-const-wf-doesnt-specialize.rs:8:29
    |
 LL | impl<const N: i32> Copy for S<N> {}
-   | -------------------------------- first implementation here
-LL | impl<const M: usize> Copy for S<M> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>`
+   |                             ^^^^
+   |
+note: required by a bound in `S`
+  --> $DIR/bad-const-wf-doesnt-specialize.rs:6:10
+   |
+LL | struct S<const L: usize>;
+   |          ^^^^^^^^^^^^^^ required by this bound in `S`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/stability-attribute/auxiliary/similar-unstable-method.rs b/tests/ui/stability-attribute/auxiliary/similar-unstable-method.rs
new file mode 100644
index 00000000000..8804186ee1a
--- /dev/null
+++ b/tests/ui/stability-attribute/auxiliary/similar-unstable-method.rs
@@ -0,0 +1,13 @@
+#![feature(staged_api)]
+#![stable(feature = "libfoo", since = "1.0.0")]
+
+#[unstable(feature = "foo", reason = "...", issue = "none")]
+pub fn foo() {}
+
+#[stable(feature = "libfoo", since = "1.0.0")]
+pub struct Foo;
+
+impl Foo {
+    #[unstable(feature = "foo", reason = "...", issue = "none")]
+    pub fn foo(&self) {}
+}
diff --git a/tests/ui/stability-attribute/issue-109177.rs b/tests/ui/stability-attribute/issue-109177.rs
new file mode 100644
index 00000000000..6d052779c6d
--- /dev/null
+++ b/tests/ui/stability-attribute/issue-109177.rs
@@ -0,0 +1,13 @@
+// aux-build: similar-unstable-method.rs
+
+extern crate similar_unstable_method;
+
+fn main() {
+    // FIXME: this function should not suggest the `foo` function.
+    similar_unstable_method::foo1();
+    //~^ ERROR cannot find function `foo1` in crate `similar_unstable_method` [E0425]
+
+    let foo = similar_unstable_method::Foo;
+    foo.foo1();
+    //~^ ERROR no method named `foo1` found for struct `Foo` in the current scope [E0599]
+}
diff --git a/tests/ui/stability-attribute/issue-109177.stderr b/tests/ui/stability-attribute/issue-109177.stderr
new file mode 100644
index 00000000000..9c2ac591ace
--- /dev/null
+++ b/tests/ui/stability-attribute/issue-109177.stderr
@@ -0,0 +1,21 @@
+error[E0425]: cannot find function `foo1` in crate `similar_unstable_method`
+  --> $DIR/issue-109177.rs:7:30
+   |
+LL |     similar_unstable_method::foo1();
+   |                              ^^^^ help: a function with a similar name exists: `foo`
+   |
+  ::: $DIR/auxiliary/similar-unstable-method.rs:5:1
+   |
+LL | pub fn foo() {}
+   | ------------ similarly named function `foo` defined here
+
+error[E0599]: no method named `foo1` found for struct `Foo` in the current scope
+  --> $DIR/issue-109177.rs:11:9
+   |
+LL |     foo.foo1();
+   |         ^^^^ method not found in `Foo`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0425, E0599.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/suggestions/bad-infer-in-trait-impl.rs b/tests/ui/suggestions/bad-infer-in-trait-impl.rs
new file mode 100644
index 00000000000..87db2636fb2
--- /dev/null
+++ b/tests/ui/suggestions/bad-infer-in-trait-impl.rs
@@ -0,0 +1,10 @@
+trait Foo {
+    fn bar();
+}
+
+impl Foo for () {
+    fn bar(s: _) {}
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/bad-infer-in-trait-impl.stderr b/tests/ui/suggestions/bad-infer-in-trait-impl.stderr
new file mode 100644
index 00000000000..418690ff85f
--- /dev/null
+++ b/tests/ui/suggestions/bad-infer-in-trait-impl.stderr
@@ -0,0 +1,14 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+  --> $DIR/bad-infer-in-trait-impl.rs:6:15
+   |
+LL |     fn bar(s: _) {}
+   |               ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL |     fn bar<T>(s: T) {}
+   |           +++    ~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/tests/ui/suggestions/chain-method-call-mutation-in-place.rs b/tests/ui/suggestions/chain-method-call-mutation-in-place.rs
index cb92ab87a8f..7a4c747961c 100644
--- a/tests/ui/suggestions/chain-method-call-mutation-in-place.rs
+++ b/tests/ui/suggestions/chain-method-call-mutation-in-place.rs
@@ -1,4 +1,8 @@
-fn main() {}
+fn main() {
+    let x: Vec<i32> = vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i); //~ ERROR mismatched types
+    vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i).sort(); //~ ERROR no method named `sort` found for unit type `()` in the current scope
+}
+
 fn foo(mut s: String) -> String {
     s.push_str("asdf") //~ ERROR mismatched types
 }
diff --git a/tests/ui/suggestions/chain-method-call-mutation-in-place.stderr b/tests/ui/suggestions/chain-method-call-mutation-in-place.stderr
index 11d9b8391f6..128160f10ad 100644
--- a/tests/ui/suggestions/chain-method-call-mutation-in-place.stderr
+++ b/tests/ui/suggestions/chain-method-call-mutation-in-place.stderr
@@ -1,5 +1,33 @@
 error[E0308]: mismatched types
-  --> $DIR/chain-method-call-mutation-in-place.rs:3:5
+  --> $DIR/chain-method-call-mutation-in-place.rs:2:23
+   |
+LL |     let x: Vec<i32> = vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i);
+   |            --------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Vec<i32>`, found `()`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `Vec<i32>`
+           found unit type `()`
+note: method `sort_by_key` modifies its receiver in-place, it is not meant to be used in method chains.
+  --> $DIR/chain-method-call-mutation-in-place.rs:2:71
+   |
+LL |     let x: Vec<i32> = vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i);
+   |                                                                       ^^^^^^^^^^^ this call modifies its receiver in-place
+
+error[E0599]: no method named `sort` found for unit type `()` in the current scope
+  --> $DIR/chain-method-call-mutation-in-place.rs:3:72
+   |
+LL |     vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i).sort();
+   |                                                                        ^^^^ method not found in `()`
+   |
+note: method `sort_by_key` modifies its receiver in-place, it is not meant to be used in method chains.
+  --> $DIR/chain-method-call-mutation-in-place.rs:3:53
+   |
+LL |     vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i).sort();
+   |                                                     ^^^^^^^^^^^ this call modifies its receiver in-place
+
+error[E0308]: mismatched types
+  --> $DIR/chain-method-call-mutation-in-place.rs:7:5
    |
 LL | fn foo(mut s: String) -> String {
    |                          ------ expected `String` because of return type
@@ -7,7 +35,7 @@ LL |     s.push_str("asdf")
    |     ^^^^^^^^^^^^^^^^^^ expected `String`, found `()`
    |
 note: method `push_str` modifies its receiver in-place
-  --> $DIR/chain-method-call-mutation-in-place.rs:3:7
+  --> $DIR/chain-method-call-mutation-in-place.rs:7:7
    |
 LL |     s.push_str("asdf")
    |     - ^^^^^^^^ this call modifies `s` in-place
@@ -15,6 +43,7 @@ LL |     s.push_str("asdf")
    |     you probably want to use this value after calling the method...
    = note: ...instead of the `()` output of method `push_str`
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0308, E0599.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
index 90ea0623952..b827beb504d 100644
--- a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
+++ b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
@@ -69,18 +69,15 @@ note: required by a bound in `Pin::<P>::new`
 error[E0308]: mismatched types
   --> $DIR/expected-boxed-future-isnt-pinned.rs:28:5
    |
+LL |   fn zap() -> BoxFuture<'static, i32> {
+   |               ----------------------- expected `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>` because of return type
 LL | /     async {
 LL | |         42
 LL | |     }
-   | |     ^
-   | |     |
-   | |_____expected `Pin<Box<...>>`, found `async` block
-   |       arguments to this function are incorrect
+   | |_____^ expected `Pin<Box<...>>`, found `async` block
    |
-   = note:     expected struct `Pin<Box<dyn Future<Output = i32> + Send>>`
+   = note:     expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>`
            found `async` block `[async block@$DIR/expected-boxed-future-isnt-pinned.rs:28:5: 30:6]`
-note: function defined here
-  --> $SRC_DIR/core/src/future/mod.rs:LL:COL
 help: you need to pin and box this expression
    |
 LL ~     Box::pin(async {
diff --git a/tests/ui/suggestions/issue-109396.rs b/tests/ui/suggestions/issue-109396.rs
new file mode 100644
index 00000000000..b6c464d45a2
--- /dev/null
+++ b/tests/ui/suggestions/issue-109396.rs
@@ -0,0 +1,12 @@
+fn main() {
+    {
+        let mut mutex = std::mem::zeroed(
+            //~^ ERROR this function takes 0 arguments but 4 arguments were supplied
+            file.as_raw_fd(),
+            //~^ ERROR expected value, found macro `file`
+            0,
+            0,
+            0,
+        );
+    }
+}
diff --git a/tests/ui/suggestions/issue-109396.stderr b/tests/ui/suggestions/issue-109396.stderr
new file mode 100644
index 00000000000..eca160e2fab
--- /dev/null
+++ b/tests/ui/suggestions/issue-109396.stderr
@@ -0,0 +1,34 @@
+error[E0423]: expected value, found macro `file`
+  --> $DIR/issue-109396.rs:5:13
+   |
+LL |             file.as_raw_fd(),
+   |             ^^^^ not a value
+
+error[E0061]: this function takes 0 arguments but 4 arguments were supplied
+  --> $DIR/issue-109396.rs:3:25
+   |
+LL |         let mut mutex = std::mem::zeroed(
+   |                         ^^^^^^^^^^^^^^^^
+LL |
+LL |             file.as_raw_fd(),
+   |             ---------------- unexpected argument
+LL |
+LL |             0,
+   |             - unexpected argument of type `{integer}`
+LL |             0,
+   |             - unexpected argument of type `{integer}`
+LL |             0,
+   |             - unexpected argument of type `{integer}`
+   |
+note: function defined here
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+help: remove the extra arguments
+   |
+LL -             file.as_raw_fd(),
+LL +             ,
+   |
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0061, E0423.
+For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/suggestions/suggest-ret-on-async-w-late.rs b/tests/ui/suggestions/suggest-ret-on-async-w-late.rs
new file mode 100644
index 00000000000..459b94f943b
--- /dev/null
+++ b/tests/ui/suggestions/suggest-ret-on-async-w-late.rs
@@ -0,0 +1,11 @@
+// edition: 2021
+
+// Make sure we don't ICE when suggesting a return type
+// for an async fn that has late-bound vars...
+
+async fn ice(_: &i32) {
+    true
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/suggest-ret-on-async-w-late.stderr b/tests/ui/suggestions/suggest-ret-on-async-w-late.stderr
new file mode 100644
index 00000000000..bff864b222b
--- /dev/null
+++ b/tests/ui/suggestions/suggest-ret-on-async-w-late.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/suggest-ret-on-async-w-late.rs:7:5
+   |
+LL | async fn ice(_: &i32) {
+   |                       - help: try adding a return type: `-> bool`
+LL |     true
+   |     ^^^^ expected `()`, found `bool`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/test-attrs/custom-test-frameworks/issue-107454.rs b/tests/ui/test-attrs/custom-test-frameworks/issue-107454.rs
new file mode 100644
index 00000000000..2bb133e8bfd
--- /dev/null
+++ b/tests/ui/test-attrs/custom-test-frameworks/issue-107454.rs
@@ -0,0 +1,10 @@
+// compile-flags: --test
+
+#![feature(custom_test_frameworks)]
+#![deny(unnameable_test_items)]
+
+fn foo() {
+    #[test_case]
+    //~^ ERROR cannot test inner items [unnameable_test_items]
+    fn test2() {}
+}
diff --git a/tests/ui/test-attrs/custom-test-frameworks/issue-107454.stderr b/tests/ui/test-attrs/custom-test-frameworks/issue-107454.stderr
new file mode 100644
index 00000000000..bd604afb79f
--- /dev/null
+++ b/tests/ui/test-attrs/custom-test-frameworks/issue-107454.stderr
@@ -0,0 +1,15 @@
+error: cannot test inner items
+  --> $DIR/issue-107454.rs:7:5
+   |
+LL |     #[test_case]
+   |     ^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-107454.rs:4:9
+   |
+LL | #![deny(unnameable_test_items)]
+   |         ^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the attribute macro `test_case` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/test-attrs/tests-listing-format-default.rs b/tests/ui/test-attrs/tests-listing-format-default.rs
new file mode 100644
index 00000000000..d5df4b57b05
--- /dev/null
+++ b/tests/ui/test-attrs/tests-listing-format-default.rs
@@ -0,0 +1,18 @@
+// no-prefer-dynamic
+// compile-flags: --test
+// run-flags: --list
+// run-pass
+// check-run-results
+
+// Checks the listing of tests with no --format arguments.
+
+#![cfg(test)]
+#[test]
+fn m_test() {}
+
+#[test]
+#[ignore = "not yet implemented"]
+fn z_test() {}
+
+#[test]
+fn a_test() {}
diff --git a/tests/ui/test-attrs/tests-listing-format-default.run.stdout b/tests/ui/test-attrs/tests-listing-format-default.run.stdout
new file mode 100644
index 00000000000..72337daf02c
--- /dev/null
+++ b/tests/ui/test-attrs/tests-listing-format-default.run.stdout
@@ -0,0 +1,5 @@
+a_test: test
+m_test: test
+z_test: test
+
+3 tests, 0 benchmarks
diff --git a/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs
new file mode 100644
index 00000000000..5247f1f8f17
--- /dev/null
+++ b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs
@@ -0,0 +1,18 @@
+// no-prefer-dynamic
+// compile-flags: --test
+// run-flags: --list --format json
+// run-fail
+// check-run-results
+
+// Checks that --format json does not work without -Zunstable-options.
+
+#![cfg(test)]
+#[test]
+fn m_test() {}
+
+#[test]
+#[ignore = "not yet implemented"]
+fn z_test() {}
+
+#[test]
+fn a_test() {}
diff --git a/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr
new file mode 100644
index 00000000000..9f6276300a0
--- /dev/null
+++ b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr
@@ -0,0 +1 @@
+error: The "json" format is only accepted on the nightly compiler
diff --git a/tests/ui/test-attrs/tests-listing-format-json.rs b/tests/ui/test-attrs/tests-listing-format-json.rs
new file mode 100644
index 00000000000..18f1521eeeb
--- /dev/null
+++ b/tests/ui/test-attrs/tests-listing-format-json.rs
@@ -0,0 +1,20 @@
+// no-prefer-dynamic
+// compile-flags: --test
+// run-flags: --list --format json -Zunstable-options
+// run-pass
+// check-run-results
+// normalize-stdout-test: "fake-test-src-base/test-attrs/" -> "$$DIR/"
+// normalize-stdout-test: "fake-test-src-base\\test-attrs\\" -> "$$DIR/"
+
+// Checks the listing of tests with --format json.
+
+#![cfg(test)]
+#[test]
+fn m_test() {}
+
+#[test]
+#[ignore = "not yet implemented"]
+fn z_test() {}
+
+#[test]
+fn a_test() {}
diff --git a/tests/ui/test-attrs/tests-listing-format-json.run.stdout b/tests/ui/test-attrs/tests-listing-format-json.run.stdout
new file mode 100644
index 00000000000..b4131e97c34
--- /dev/null
+++ b/tests/ui/test-attrs/tests-listing-format-json.run.stdout
@@ -0,0 +1,5 @@
+{ "type": "suite", "event": "discovery" }
+{ "type": "test", "event": "discovered", "name": "a_test", "ignore": false, "ignore_message": "", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 20, "start_col": 4, "end_line": 20, "end_col": 10 }
+{ "type": "test", "event": "discovered", "name": "m_test", "ignore": false, "ignore_message": "", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 13, "start_col": 4, "end_line": 13, "end_col": 10 }
+{ "type": "test", "event": "discovered", "name": "z_test", "ignore": true, "ignore_message": "not yet implemented", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 17, "start_col": 4, "end_line": 17, "end_col": 10 }
+{ "type": "suite", "event": "completed", "tests": 3, "benchmarks": 0, "total": 3, "ignored": 1 }
diff --git a/tests/ui/test-attrs/tests-listing-format-terse.rs b/tests/ui/test-attrs/tests-listing-format-terse.rs
new file mode 100644
index 00000000000..7835f71759c
--- /dev/null
+++ b/tests/ui/test-attrs/tests-listing-format-terse.rs
@@ -0,0 +1,18 @@
+// no-prefer-dynamic
+// compile-flags: --test
+// run-flags: --list --format terse
+// run-pass
+// check-run-results
+
+// Checks the listing of tests with --format terse.
+
+#![cfg(test)]
+#[test]
+fn m_test() {}
+
+#[test]
+#[ignore = "not yet implemented"]
+fn z_test() {}
+
+#[test]
+fn a_test() {}
diff --git a/tests/ui/test-attrs/tests-listing-format-terse.run.stdout b/tests/ui/test-attrs/tests-listing-format-terse.run.stdout
new file mode 100644
index 00000000000..22afe104bfb
--- /dev/null
+++ b/tests/ui/test-attrs/tests-listing-format-terse.run.stdout
@@ -0,0 +1,3 @@
+a_test: test
+m_test: test
+z_test: test
diff --git a/tests/ui/traits/cycle-cache-err-60010.stderr b/tests/ui/traits/cycle-cache-err-60010.stderr
index eeee997608e..2ff16b4af38 100644
--- a/tests/ui/traits/cycle-cache-err-60010.stderr
+++ b/tests/ui/traits/cycle-cache-err-60010.stderr
@@ -1,22 +1,9 @@
-error[E0275]: overflow evaluating the requirement `SalsaStorage: RefUnwindSafe`
+error[E0275]: overflow evaluating the requirement `RootDatabase: RefUnwindSafe`
   --> $DIR/cycle-cache-err-60010.rs:27:13
    |
 LL |     _parse: <ParseQuery as Query<RootDatabase>>::Data,
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: required because it appears within the type `PhantomData<SalsaStorage>`
-   = note: required because it appears within the type `Unique<SalsaStorage>`
-   = note: required because it appears within the type `Box<SalsaStorage>`
-note: required because it appears within the type `Runtime<RootDatabase>`
-  --> $DIR/cycle-cache-err-60010.rs:23:8
-   |
-LL | struct Runtime<DB: Database> {
-   |        ^^^^^^^
-note: required because it appears within the type `RootDatabase`
-  --> $DIR/cycle-cache-err-60010.rs:20:8
-   |
-LL | struct RootDatabase {
-   |        ^^^^^^^^^^^^
 note: required for `RootDatabase` to implement `SourceDatabase`
   --> $DIR/cycle-cache-err-60010.rs:44:9
    |
diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.rs b/tests/ui/traits/issue-91949-hangs-on-recursion.rs
index 6474b2b38e1..4eca643a92d 100644
--- a/tests/ui/traits/issue-91949-hangs-on-recursion.rs
+++ b/tests/ui/traits/issue-91949-hangs-on-recursion.rs
@@ -1,6 +1,6 @@
 // build-fail
 // compile-flags: -Zinline-mir=no
-// error-pattern: overflow evaluating the requirement `(): Sized`
+// error-pattern: overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()`
 // error-pattern: function cannot return without recursing
 // normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
 
diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr
index 1f18c5daf66..144990d50f0 100644
--- a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr
+++ b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr
@@ -12,11 +12,17 @@ LL |       recurse(IteratorOfWrapped(elements).map(|t| t.0))
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-error[E0275]: overflow evaluating the requirement `(): Sized`
+error[E0275]: overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()`
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`)
-   = note: required for `std::iter::Empty<()>` to implement `Iterator`
-   = note: 171 redundant requirements hidden
+note: required for `IteratorOfWrapped<(), std::iter::Empty<()>>` to implement `Iterator`
+  --> $DIR/issue-91949-hangs-on-recursion.rs:16:32
+   |
+LL | impl<T, I: Iterator<Item = T>> Iterator for IteratorOfWrapped<T, I> {
+   |                     --------   ^^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^
+   |                     |
+   |                     unsatisfied trait bound introduced here
+   = note: 256 redundant requirements hidden
    = note: required for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<..., ...>>, ...>>, ...>>` to implement `Iterator`
    = note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type-hash.txt'
 
diff --git a/tests/ui/traits/new-solver/fn-trait.rs b/tests/ui/traits/new-solver/fn-trait.rs
index d566ead105c..0599e51d7ad 100644
--- a/tests/ui/traits/new-solver/fn-trait.rs
+++ b/tests/ui/traits/new-solver/fn-trait.rs
@@ -1,5 +1,4 @@
 // compile-flags: -Ztrait-solver=next
-// check-pass
 
 fn require_fn(_: impl Fn() -> i32) {}
 
@@ -7,7 +6,27 @@ fn f() -> i32 {
     1i32
 }
 
+extern "C" fn g() -> i32 {
+    2i32
+}
+
+unsafe fn h() -> i32 {
+    2i32
+}
+
 fn main() {
     require_fn(f);
     require_fn(f as fn() -> i32);
+    require_fn(f as unsafe fn() -> i32);
+    //~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32`
+    //~| ERROR: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32`
+    require_fn(g);
+    //~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}`
+    //~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 {g} as FnOnce<()>>::Output == i32`
+    require_fn(g as extern "C" fn() -> i32);
+    //~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32`
+    //~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32`
+    require_fn(h);
+    //~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}`
+    //~| ERROR: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32`
 }
diff --git a/tests/ui/traits/new-solver/fn-trait.stderr b/tests/ui/traits/new-solver/fn-trait.stderr
new file mode 100644
index 00000000000..d52bcaf25b8
--- /dev/null
+++ b/tests/ui/traits/new-solver/fn-trait.stderr
@@ -0,0 +1,124 @@
+error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32`
+  --> $DIR/fn-trait.rs:20:16
+   |
+LL |     require_fn(f as unsafe fn() -> i32);
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Fn<()>` is not implemented for `unsafe fn() -> i32`
+   = note: wrap the `unsafe fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:23
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                       ^^^^^^^^^^^ required by this bound in `require_fn`
+
+error[E0271]: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32`
+  --> $DIR/fn-trait.rs:20:16
+   |
+LL |     require_fn(f as unsafe fn() -> i32);
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:31
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                               ^^^ required by this bound in `require_fn`
+
+error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}`
+  --> $DIR/fn-trait.rs:23:16
+   |
+LL |     require_fn(g);
+   |     ---------- ^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32 {g}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Fn<()>` is not implemented for fn item `extern "C" fn() -> i32 {g}`
+   = note: wrap the `extern "C" fn() -> i32 {g}` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:23
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                       ^^^^^^^^^^^ required by this bound in `require_fn`
+
+error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 {g} as FnOnce<()>>::Output == i32`
+  --> $DIR/fn-trait.rs:23:16
+   |
+LL |     require_fn(g);
+   |     ---------- ^ types differ
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:31
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                               ^^^ required by this bound in `require_fn`
+
+error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32`
+  --> $DIR/fn-trait.rs:26:16
+   |
+LL |     require_fn(g as extern "C" fn() -> i32);
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Fn<()>` is not implemented for `extern "C" fn() -> i32`
+   = note: wrap the `extern "C" fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:23
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                       ^^^^^^^^^^^ required by this bound in `require_fn`
+
+error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32`
+  --> $DIR/fn-trait.rs:26:16
+   |
+LL |     require_fn(g as extern "C" fn() -> i32);
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:31
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                               ^^^ required by this bound in `require_fn`
+
+error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}`
+  --> $DIR/fn-trait.rs:29:16
+   |
+LL |     require_fn(h);
+   |     ---------- ^ call the function in a closure: `|| unsafe { /* code */ }`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() -> i32 {h}`
+   = note: wrap the `unsafe fn() -> i32 {h}` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:23
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                       ^^^^^^^^^^^ required by this bound in `require_fn`
+
+error[E0271]: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32`
+  --> $DIR/fn-trait.rs:29:16
+   |
+LL |     require_fn(h);
+   |     ---------- ^ types differ
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:31
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                               ^^^ required by this bound in `require_fn`
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.rs b/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.rs
new file mode 100644
index 00000000000..91c6dfb8e0a
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.rs
@@ -0,0 +1,11 @@
+#![feature(non_lifetime_binders)]
+//~^ WARN the feature `non_lifetime_binders` is incomplete
+
+fn b()
+where
+    for<const C: usize> [(); C]: Copy,
+    //~^ ERROR cannot capture late-bound const parameter in a constant
+{
+}
+
+fn main() {}
diff --git a/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.stderr b/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.stderr
new file mode 100644
index 00000000000..69bb605bf41
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.stderr
@@ -0,0 +1,19 @@
+warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/capture-late-ct-in-anon.rs:1:12
+   |
+LL | #![feature(non_lifetime_binders)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: cannot capture late-bound const parameter in a constant
+  --> $DIR/capture-late-ct-in-anon.rs:6:30
+   |
+LL |     for<const C: usize> [(); C]: Copy,
+   |         --------------       ^
+   |         |
+   |         parameter defined here
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs
new file mode 100644
index 00000000000..50f0152e904
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs
@@ -0,0 +1,11 @@
+#![feature(non_lifetime_binders)]
+//~^ WARN the feature `non_lifetime_binders` is incomplete
+
+fn f()
+where
+    for<B> B::Item: Send,
+    //~^ ERROR ambiguous associated type
+{
+}
+
+fn main() {}
diff --git a/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr
new file mode 100644
index 00000000000..be6955c111e
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr
@@ -0,0 +1,18 @@
+warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/missing-assoc-item.rs:1:12
+   |
+LL | #![feature(non_lifetime_binders)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0223]: ambiguous associated type
+  --> $DIR/missing-assoc-item.rs:6:12
+   |
+LL |     for<B> B::Item: Send,
+   |            ^^^^^^^ help: use the fully-qualified path: `<B as IntoIterator>::Item`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0223`.
diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs
new file mode 100644
index 00000000000..a635edb4485
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs
@@ -0,0 +1,24 @@
+#![feature(non_lifetime_binders)]
+//~^ WARN the feature `non_lifetime_binders` is incomplete
+
+trait Foo: for<T> Bar<T> {}
+
+trait Bar<T: ?Sized> {
+    fn method(&self) {}
+}
+
+fn needs_bar(x: &(impl Bar<i32> + ?Sized)) {
+    x.method();
+}
+
+impl Foo for () {}
+
+impl<T: ?Sized> Bar<T> for () {}
+
+fn main() {
+    let x: &dyn Foo = &();
+    //~^ ERROR the trait `Foo` cannot be made into an object
+    //~| ERROR the trait `Foo` cannot be made into an object
+    needs_bar(x);
+    //~^ ERROR the trait `Foo` cannot be made into an object
+}
diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr
new file mode 100644
index 00000000000..47fa29b6648
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr
@@ -0,0 +1,56 @@
+warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/supertrait-object-safety.rs:1:12
+   |
+LL | #![feature(non_lifetime_binders)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/supertrait-object-safety.rs:19:23
+   |
+LL |     let x: &dyn Foo = &();
+   |                       ^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/supertrait-object-safety.rs:4:12
+   |
+LL | trait Foo: for<T> Bar<T> {}
+   |       ---  ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables
+   |       |
+   |       this trait cannot be made into an object...
+   = note: required for `&()` to implement `CoerceUnsized<&dyn Foo>`
+   = note: required by cast to type `&dyn Foo`
+
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/supertrait-object-safety.rs:19:12
+   |
+LL |     let x: &dyn Foo = &();
+   |            ^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/supertrait-object-safety.rs:4:12
+   |
+LL | trait Foo: for<T> Bar<T> {}
+   |       ---  ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables
+   |       |
+   |       this trait cannot be made into an object...
+
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/supertrait-object-safety.rs:22:5
+   |
+LL |     needs_bar(x);
+   |     ^^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/supertrait-object-safety.rs:4:12
+   |
+LL | trait Foo: for<T> Bar<T> {}
+   |       ---  ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables
+   |       |
+   |       this trait cannot be made into an object...
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs
index a450dbb82d1..e6f7dc410b6 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.rs
+++ b/tests/ui/typeck/typeck_type_placeholder_item.rs
@@ -228,5 +228,4 @@ fn evens_squared(n: usize) -> _ {
 
 const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
 //~^ ERROR the trait bound
-//~| ERROR the trait bound
 //~| ERROR the placeholder
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr
index bc6c9fd0779..9144ab9e3a6 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr
@@ -437,19 +437,6 @@ LL | fn evens_squared(n: usize) -> _ {
    |                               not allowed in type signatures
    |                               help: replace with an appropriate return type: `impl Iterator<Item = usize>`
 
-error[E0277]: the trait bound `std::ops::Range<{integer}>: Iterator` is not satisfied
-  --> $DIR/typeck_type_placeholder_item.rs:229:22
-   |
-LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
-   |                      ^^^^^^ `std::ops::Range<{integer}>` is not an iterator
-   |
-   = help: the trait `~const Iterator` is not implemented for `std::ops::Range<{integer}>`
-note: the trait `Iterator` is implemented for `std::ops::Range<{integer}>`, but that implementation is not `const`
-  --> $DIR/typeck_type_placeholder_item.rs:229:14
-   |
-LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
-   |              ^^^^^^^
-
 error[E0277]: the trait bound `Filter<std::ops::Range<{integer}>, [closure@$DIR/typeck_type_placeholder_item.rs:229:29: 229:32]>: Iterator` is not satisfied
   --> $DIR/typeck_type_placeholder_item.rs:229:45
    |
@@ -677,7 +664,7 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              help: replace with the correct type: `i32`
 
-error: aborting due to 73 previous errors
+error: aborting due to 72 previous errors
 
 Some errors have detailed explanations: E0121, E0277, E0282, E0403.
 For more information about an error, try `rustc --explain E0121`.
diff --git a/tests/ui/unpretty/flattened-format-args.rs b/tests/ui/unpretty/flattened-format-args.rs
new file mode 100644
index 00000000000..705dded169a
--- /dev/null
+++ b/tests/ui/unpretty/flattened-format-args.rs
@@ -0,0 +1,8 @@
+// compile-flags: -Zunpretty=hir -Zflatten-format-args=yes
+// check-pass
+
+fn main() {
+    let x = 1;
+    // Should flatten to println!("a 123 b {x} xyz\n"):
+    println!("a {} {}", format_args!("{} b {x}", 123), "xyz");
+}
diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout
new file mode 100644
index 00000000000..a8fe8da0024
--- /dev/null
+++ b/tests/ui/unpretty/flattened-format-args.stdout
@@ -0,0 +1,16 @@
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+// compile-flags: -Zunpretty=hir -Zflatten-format-args=yes
+// check-pass
+
+fn main() {
+        let x = 1;
+        // Should flatten to println!("a 123 b {x} xyz\n"):
+        {
+                ::std::io::_print(<#[lang = "format_arguments"]>::new_v1(&["a 123 b ",
+                                    " xyz\n"],
+                        &[<#[lang = "format_argument"]>::new_display(&x)]));
+            };
+    }
diff --git a/triagebot.toml b/triagebot.toml
index a81f66fe168..9ffe2e72cab 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -492,7 +492,6 @@ compiler-team = [
     "@oli-obk",
     "@lcnr",
     "@wesleywiser",
-    "@michaelwoerister",
 ]
 compiler-team-contributors = [
     "@compiler-errors",