about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc/src/main.rs4
-rw-r--r--compiler/rustc_ast/Cargo.toml2
-rw-r--r--compiler/rustc_ast/src/ast.rs25
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs14
-rw-r--r--compiler/rustc_ast/src/visit.rs5
-rw-r--r--compiler/rustc_ast_lowering/Cargo.toml2
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs158
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs65
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs16
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs38
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs59
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs16
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs126
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs71
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs62
-rw-r--r--compiler/rustc_attr/src/session_diagnostics.rs90
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs41
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs11
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs156
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs100
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs23
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs269
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs26
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs49
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs19
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs2
-rw-r--r--compiler/rustc_builtin_macros/Cargo.toml2
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs104
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs37
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs15
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml99
-rw-r--r--compiler/rustc_codegen_cranelift/.gitignore6
-rw-r--r--compiler/rustc_codegen_cranelift/.vscode/settings.json6
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock62
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml14
-rw-r--r--compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock38
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs52
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/abi_checker.rs60
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/build_backend.rs16
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/config.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/mod.rs21
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/prepare.rs186
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/rustc_info.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/tests.rs179
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/utils.rs46
-rwxr-xr-xcompiler/rustc_codegen_cranelift/clean_all.sh6
-rw-r--r--compiler/rustc_codegen_cranelift/config.txt2
-rw-r--r--compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch29
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch36
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch96
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch47
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh6
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh8
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs53
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/allocator.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/src/archive.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs18
-rw-r--r--compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs17
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs90
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs51
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs22
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs62
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs128
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs14
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/num.rs61
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs40
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs48
-rw-r--r--compiler/rustc_codegen_cranelift/src/vtable.rs26
-rw-r--r--compiler/rustc_codegen_gcc/src/allocator.rs11
-rw-r--r--compiler/rustc_codegen_gcc/src/archive.rs1
-rw-r--r--compiler/rustc_codegen_gcc/src/errors.rs46
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs4
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/asm.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs31
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs111
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs20
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs18
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs143
-rw-r--r--compiler/rustc_codegen_ssa/src/common.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs127
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs116
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs20
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs27
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs209
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs7
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs72
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs16
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs4
-rw-r--r--compiler/rustc_const_eval/src/errors.rs60
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs110
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs11
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs13
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs3
-rw-r--r--compiler/rustc_const_eval/src/lib.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs3
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs6
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs9
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs30
-rw-r--r--compiler/rustc_const_eval/src/util/call_kind.rs20
-rw-r--r--compiler/rustc_const_eval/src/util/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs (renamed from compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs)25
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_data_structures/src/flock/linux.rs7
-rw-r--r--compiler/rustc_data_structures/src/graph/vec_graph/mod.rs4
-rw-r--r--compiler/rustc_data_structures/src/lib.rs2
-rw-r--r--compiler/rustc_data_structures/src/sso/set.rs2
-rw-r--r--compiler/rustc_data_structures/src/transitive_relation.rs12
-rw-r--r--compiler/rustc_data_structures/src/unord.rs382
-rw-r--r--compiler/rustc_driver/src/lib.rs47
-rw-r--r--compiler/rustc_driver/src/session_diagnostics.rs14
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0210.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0382.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0732.md4
-rw-r--r--compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl2
-rw-r--r--compiler/rustc_error_messages/locales/en-US/errors.ftl13
-rw-r--r--compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl19
-rw-r--r--compiler/rustc_error_messages/locales/en-US/infer.ftl4
-rw-r--r--compiler/rustc_error_messages/locales/en-US/metadata.ftl18
-rw-r--r--compiler/rustc_error_messages/locales/en-US/middle.ftl4
-rw-r--r--compiler/rustc_error_messages/locales/en-US/monomorphize.ftl3
-rw-r--r--compiler/rustc_error_messages/locales/en-US/passes.ftl9
-rw-r--r--compiler/rustc_error_messages/locales/en-US/session.ftl18
-rw-r--r--compiler/rustc_error_messages/src/lib.rs1
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs231
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs5
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs222
-rw-r--r--compiler/rustc_errors/src/emitter.rs36
-rw-r--r--compiler/rustc_errors/src/json.rs8
-rw-r--r--compiler/rustc_errors/src/json/tests.rs1
-rw-r--r--compiler/rustc_errors/src/lib.rs41
-rw-r--r--compiler/rustc_expand/src/base.rs49
-rw-r--r--compiler/rustc_expand/src/config.rs10
-rw-r--r--compiler/rustc_expand/src/errors.rs12
-rw-r--r--compiler/rustc_expand/src/expand.rs72
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs7
-rw-r--r--compiler/rustc_expand/src/placeholders.rs8
-rw-r--r--compiler/rustc_expand/src/tests.rs1
-rw-r--r--compiler/rustc_feature/src/accepted.rs4
-rw-r--r--compiler/rustc_feature/src/active.rs9
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs42
-rw-r--r--compiler/rustc_hir/src/hir.rs72
-rw-r--r--compiler/rustc_hir/src/intravisit.rs729
-rw-r--r--compiler/rustc_hir/src/lang_items.rs212
-rw-r--r--compiler/rustc_hir/src/lib.rs2
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs8
-rw-r--r--compiler/rustc_hir/src/weak_lang_items.rs59
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs118
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs511
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_method.rs125
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs110
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs502
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs178
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs58
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/unsafety.rs32
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs118
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/collect/lifetimes.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs35
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs115
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs201
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs46
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs57
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/test.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/variance/test.rs7
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs6
-rw-r--r--compiler/rustc_hir_typeck/Cargo.toml28
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs (renamed from compiler/rustc_hir_analysis/src/check/_match.rs)11
-rw-r--r--compiler/rustc_hir_typeck/src/autoderef.rs (renamed from compiler/rustc_hir_analysis/src/check/autoderef.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs (renamed from compiler/rustc_hir_analysis/src/check/callee.rs)5
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs (renamed from compiler/rustc_hir_analysis/src/check/cast.rs)114
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs268
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs (renamed from compiler/rustc_hir_analysis/src/check/closure.rs)105
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs (renamed from compiler/rustc_hir_analysis/src/check/coercion.rs)64
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs (renamed from compiler/rustc_hir_analysis/src/check/demand.rs)71
-rw-r--r--compiler/rustc_hir_typeck/src/diverges.rs (renamed from compiler/rustc_hir_analysis/src/check/diverges.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs127
-rw-r--r--compiler/rustc_hir_typeck/src/expectation.rs (renamed from compiler/rustc_hir_analysis/src/check/expectation.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs (renamed from compiler/rustc_hir_analysis/src/check/expr.rs)64
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs (renamed from compiler/rustc_hir_analysis/src/expr_use_visitor.rs)13
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs (renamed from compiler/rustc_hir_analysis/src/check/fallback.rs)4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs (renamed from compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs)118
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs (renamed from compiler/rustc_hir_analysis/src/check/fn_ctxt/arg_matrix.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs (renamed from compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs)45
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs (renamed from compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs)13
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs (renamed from compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs)66
-rw-r--r--compiler/rustc_hir_typeck/src/gather_locals.rs (renamed from compiler/rustc_hir_analysis/src/check/gather_locals.rs)3
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs (renamed from compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_build.rs)2
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs (renamed from compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_propagate.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs (renamed from compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_visualize.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs (renamed from compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges.rs)2
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs (renamed from compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs)15
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs (renamed from compiler/rustc_hir_analysis/src/check/generator_interior.rs)24
-rw-r--r--compiler/rustc_hir_typeck/src/inherited.rs (renamed from compiler/rustc_hir_analysis/src/check/inherited.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs108
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs507
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs (renamed from compiler/rustc_hir_analysis/src/mem_categorization.rs)3
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs (renamed from compiler/rustc_hir_analysis/src/check/method/confirm.rs)4
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs (renamed from compiler/rustc_hir_analysis/src/check/method/mod.rs)4
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude2021.rs (renamed from compiler/rustc_hir_analysis/src/check/method/prelude2021.rs)9
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs (renamed from compiler/rustc_hir_analysis/src/check/method/probe.rs)20
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs (renamed from compiler/rustc_hir_analysis/src/check/method/suggest.rs)115
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs (renamed from compiler/rustc_hir_analysis/src/check/op.rs)2
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs (renamed from compiler/rustc_hir_analysis/src/check/pat.rs)3
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs (renamed from compiler/rustc_hir_analysis/src/check/place_op.rs)4
-rw-r--r--compiler/rustc_hir_typeck/src/rvalue_scopes.rs (renamed from compiler/rustc_hir_analysis/src/check/rvalue_scopes.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs (renamed from compiler/rustc_hir_analysis/src/check/upvar.rs)2
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs (renamed from compiler/rustc_hir_analysis/src/check/writeback.rs)54
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs8
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs144
-rw-r--r--compiler/rustc_infer/src/errors/note_and_explain.rs4
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs16
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs26
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs17
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs18
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs21
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs23
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs11
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs17
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs32
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs5
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs39
-rw-r--r--compiler/rustc_interface/Cargo.toml1
-rw-r--r--compiler/rustc_interface/src/errors.rs28
-rw-r--r--compiler/rustc_interface/src/interface.rs109
-rw-r--r--compiler/rustc_interface/src/passes.rs17
-rw-r--r--compiler/rustc_interface/src/proc_macro_decls.rs2
-rw-r--r--compiler/rustc_interface/src/tests.rs15
-rw-r--r--compiler/rustc_interface/src/util.rs122
-rw-r--r--compiler/rustc_lexer/src/lib.rs23
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs8
-rw-r--r--compiler/rustc_lint/src/builtin.rs291
-rw-r--r--compiler/rustc_lint/src/context.rs23
-rw-r--r--compiler/rustc_lint/src/enum_intrinsics_non_enums.rs8
-rw-r--r--compiler/rustc_lint/src/errors.rs59
-rw-r--r--compiler/rustc_lint/src/expect.rs4
-rw-r--r--compiler/rustc_lint/src/hidden_unicode_codepoints.rs14
-rw-r--r--compiler/rustc_lint/src/internal.rs36
-rw-r--r--compiler/rustc_lint/src/late.rs8
-rw-r--r--compiler/rustc_lint/src/levels.rs6
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/methods.rs10
-rw-r--r--compiler/rustc_lint/src/non_ascii_idents.rs14
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs65
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs26
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs6
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs23
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs4
-rw-r--r--compiler/rustc_lint/src/redundant_semicolon.rs4
-rw-r--r--compiler/rustc_lint/src/traits.rs6
-rw-r--r--compiler/rustc_lint/src/types.rs206
-rw-r--r--compiler/rustc_lint/src/unused.rs44
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs73
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp2
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs7
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs37
-rw-r--r--compiler/rustc_macros/src/diagnostics/fluent.rs65
-rw-r--r--compiler/rustc_macros/src/diagnostics/mod.rs16
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs68
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs244
-rw-r--r--compiler/rustc_macros/src/query.rs52
-rw-r--r--compiler/rustc_metadata/src/creader.rs97
-rw-r--r--compiler/rustc_metadata/src/errors.rs247
-rw-r--r--compiler/rustc_metadata/src/foreign_modules.rs6
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs18
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs88
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs23
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs191
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs10
-rw-r--r--compiler/rustc_middle/Cargo.toml2
-rw-r--r--compiler/rustc_middle/src/arena.rs4
-rw-r--r--compiler/rustc_middle/src/error.rs21
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs16
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs8
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/lint.rs33
-rw-r--r--compiler/rustc_middle/src/macros.rs13
-rw-r--r--compiler/rustc_middle/src/middle/lang_items.rs4
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs227
-rw-r--r--compiler/rustc_middle/src/mir/interpret/pointer.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs28
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs56
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs6
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs48
-rw-r--r--compiler/rustc_middle/src/mir/type_visitable.rs32
-rw-r--r--compiler/rustc_middle/src/query/mod.rs239
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs5
-rw-r--r--compiler/rustc_middle/src/traits/specialization_graph.rs19
-rw-r--r--compiler/rustc_middle/src/ty/abstract_const.rs4
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs3
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs1
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs4
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs15
-rw-r--r--compiler/rustc_middle/src/ty/context.rs104
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs8
-rw-r--r--compiler/rustc_middle/src/ty/erase_regions.rs5
-rw-r--r--compiler/rustc_middle/src/ty/error.rs6
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs18
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs64
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs145
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs204
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs258
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs10
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs127
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs21
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs218
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs1
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs11
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs53
-rw-r--r--compiler/rustc_middle/src/ty/query.rs4
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs15
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs26
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs5
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs56
-rw-r--r--compiler/rustc_middle/src/ty/util.rs23
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs56
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs16
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs55
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs12
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs6
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs42
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs10
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/errors.rs20
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs6
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs2
-rw-r--r--compiler/rustc_mir_transform/src/deduce_param_attrs.rs248
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs25
-rw-r--r--compiler/rustc_mir_transform/src/marker.rs20
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs89
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs8
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs45
-rw-r--r--compiler/rustc_monomorphize/src/errors.rs26
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/default.rs6
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs40
-rw-r--r--compiler/rustc_parse/src/errors.rs403
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs9
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs19
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs28
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs13
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs30
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs111
-rw-r--r--compiler/rustc_parse/src/parser/item.rs2
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs32
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs20
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs65
-rw-r--r--compiler/rustc_parse_format/src/lib.rs28
-rw-r--r--compiler/rustc_parse_format/src/tests.rs15
-rw-r--r--compiler/rustc_passes/src/check_attr.rs65
-rw-r--r--compiler/rustc_passes/src/dead.rs59
-rw-r--r--compiler/rustc_passes/src/diagnostic_items.rs8
-rw-r--r--compiler/rustc_passes/src/entry.rs20
-rw-r--r--compiler/rustc_passes/src/errors.rs414
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs8
-rw-r--r--compiler/rustc_passes/src/lang_items.rs36
-rw-r--r--compiler/rustc_passes/src/layout_test.rs6
-rw-r--r--compiler/rustc_passes/src/reachable.rs40
-rw-r--r--compiler/rustc_passes/src/stability.rs56
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs24
-rw-r--r--compiler/rustc_plugin_impl/src/errors.rs4
-rw-r--r--compiler/rustc_privacy/src/errors.rs24
-rw-r--r--compiler/rustc_privacy/src/lib.rs303
-rw-r--r--compiler/rustc_query_impl/Cargo.toml2
-rw-r--r--compiler/rustc_query_impl/src/lib.rs11
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs6
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs13
-rw-r--r--compiler/rustc_query_system/Cargo.toml2
-rw-r--r--compiler/rustc_query_system/src/error.rs30
-rw-r--r--compiler/rustc_query_system/src/query/config.rs2
-rw-r--r--compiler/rustc_resolve/src/access_levels.rs180
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs55
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs8
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs96
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs200
-rw-r--r--compiler/rustc_resolve/src/ident.rs83
-rw-r--r--compiler/rustc_resolve/src/imports.rs185
-rw-r--r--compiler/rustc_resolve/src/late.rs330
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs237
-rw-r--r--compiler/rustc_resolve/src/lib.rs97
-rw-r--r--compiler/rustc_resolve/src/macros.rs16
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs78
-rw-r--r--compiler/rustc_save_analysis/src/errors.rs2
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs22
-rw-r--r--compiler/rustc_save_analysis/src/sig.rs10
-rw-r--r--compiler/rustc_serialize/Cargo.toml2
-rw-r--r--compiler/rustc_session/src/config.rs79
-rw-r--r--compiler/rustc_session/src/config/sigpipe.rs13
-rw-r--r--compiler/rustc_session/src/errors.rs143
-rw-r--r--compiler/rustc_session/src/options.rs8
-rw-r--r--compiler/rustc_session/src/parse.rs6
-rw-r--r--compiler/rustc_session/src/session.rs156
-rw-r--r--compiler/rustc_session/src/utils.rs11
-rw-r--r--compiler/rustc_span/src/lib.rs13
-rw-r--r--compiler/rustc_span/src/source_map.rs44
-rw-r--r--compiler/rustc_span/src/source_map/tests.rs45
-rw-r--r--compiler/rustc_span/src/symbol.rs10
-rw-r--r--compiler/rustc_symbol_mangling/src/errors.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs8
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs2
-rw-r--r--compiler/rustc_target/src/spec/abi.rs290
-rw-r--r--compiler/rustc_target/src/spec/apple/tests.rs20
-rw-r--r--compiler/rustc_target/src/spec/apple_sdk_base.rs21
-rw-r--r--compiler/rustc_target/src/spec/mipsel_sony_psx.rs37
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_ios.rs2
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_tvos.rs2
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs2
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs23
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs49
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs45
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs36
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs241
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs31
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs38
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs29
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs48
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs51
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs4
-rw-r--r--compiler/rustc_traits/src/lib.rs1
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs3
-rw-r--r--compiler/rustc_traits/src/normalize_projection_ty.rs7
-rw-r--r--compiler/rustc_traits/src/type_op.rs117
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs3
-rw-r--r--compiler/rustc_transmute/src/lib.rs2
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs43
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs16
-rw-r--r--compiler/rustc_ty_utils/src/errors.rs48
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs4
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs5
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs4
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs76
-rw-r--r--compiler/rustc_type_ir/src/lib.rs8
-rw-r--r--compiler/rustc_type_ir/src/sty.rs14
489 files changed, 12932 insertions, 9759 deletions
diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs
index 0de1a781913..e21c9b66044 100644
--- a/compiler/rustc/src/main.rs
+++ b/compiler/rustc/src/main.rs
@@ -1,3 +1,5 @@
+#![feature(unix_sigpipe)]
+
 // A note about jemalloc: rustc uses jemalloc when built for CI and
 // distribution. The obvious way to do this is with the `#[global_allocator]`
 // mechanism. However, for complicated reasons (see
@@ -23,6 +25,7 @@
 // libraries. So we must reference jemalloc symbols one way or another, because
 // this file is the only object code in the rustc executable.
 
+#[unix_sigpipe = "sig_dfl"]
 fn main() {
     // See the comment at the top of this file for an explanation of this.
     #[cfg(feature = "jemalloc-sys")]
@@ -58,6 +61,5 @@ fn main() {
         }
     }
 
-    rustc_driver::set_sigpipe_handler();
     rustc_driver::main()
 }
diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml
index fcbf9681825..9253b7e6891 100644
--- a/compiler/rustc_ast/Cargo.toml
+++ b/compiler/rustc_ast/Cargo.toml
@@ -14,5 +14,5 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_span = { path = "../rustc_span" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
 tracing = "0.1"
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 60b7f2e4c22..4ef43735a62 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1112,24 +1112,6 @@ pub struct Expr {
 }
 
 impl Expr {
-    /// Returns `true` if this expression would be valid somewhere that expects a value;
-    /// for example, an `if` condition.
-    pub fn returns(&self) -> bool {
-        if let ExprKind::Block(ref block, _) = self.kind {
-            match block.stmts.last().map(|last_stmt| &last_stmt.kind) {
-                // Implicit return
-                Some(StmtKind::Expr(_)) => true,
-                // Last statement is an explicit return?
-                Some(StmtKind::Semi(expr)) => matches!(expr.kind, ExprKind::Ret(_)),
-                // This is a block that doesn't end in either an implicit or explicit return.
-                _ => false,
-            }
-        } else {
-            // This is not a block, it is a value.
-            true
-        }
-    }
-
     /// Is this expr either `N`, or `{ N }`.
     ///
     /// If this is not the case, name resolution does not resolve `N` when using
@@ -2060,8 +2042,11 @@ impl TyKind {
     }
 
     pub fn is_simple_path(&self) -> Option<Symbol> {
-        if let TyKind::Path(None, Path { segments, .. }) = &self && segments.len() == 1 {
-            Some(segments[0].ident.name)
+        if let TyKind::Path(None, Path { segments, .. }) = &self
+            && let [segment] = &segments[..]
+            && segment.args.is_none()
+        {
+            Some(segment.ident.name)
         } else {
             None
         }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 25022a02f4b..b970e57e017 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -152,6 +152,12 @@ pub trait MutVisitor: Sized {
         noop_visit_expr(e, self);
     }
 
+    /// This method is a hack to workaround unstable of `stmt_expr_attributes`.
+    /// It can be removed once that feature is stabilized.
+    fn visit_method_receiver_expr(&mut self, ex: &mut P<Expr>) {
+        self.visit_expr(ex)
+    }
+
     fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
         noop_filter_map_expr(e, self)
     }
@@ -1301,7 +1307,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
             vis.visit_ident(ident);
             vis.visit_id(id);
             visit_opt(args, |args| vis.visit_generic_args(args));
-            vis.visit_expr(receiver);
+            vis.visit_method_receiver_expr(receiver);
             visit_exprs(exprs, vis);
             vis.visit_span(span);
         }
@@ -1589,3 +1595,9 @@ impl DummyAstNode for Crate {
         }
     }
 }
+
+impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNodeWrapper<N, T> {
+    fn dummy() -> Self {
+        crate::ast_traits::AstNodeWrapper::new(N::dummy(), T::dummy())
+    }
+}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index e752cc7dc2d..6f56c1ef0e8 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -140,6 +140,11 @@ pub trait Visitor<'ast>: Sized {
     fn visit_expr(&mut self, ex: &'ast Expr) {
         walk_expr(self, ex)
     }
+    /// This method is a hack to workaround unstable of `stmt_expr_attributes`.
+    /// It can be removed once that feature is stabilized.
+    fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) {
+        self.visit_expr(ex)
+    }
     fn visit_expr_post(&mut self, _ex: &'ast Expr) {}
     fn visit_ty(&mut self, t: &'ast Ty) {
         walk_ty(self, t)
diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml
index ce1c8d4997d..6a59b9e6151 100644
--- a/compiler/rustc_ast_lowering/Cargo.toml
+++ b/compiler/rustc_ast_lowering/Cargo.toml
@@ -21,5 +21,5 @@ rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
 tracing = "0.1"
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 54c83fb7604..450cdf246b1 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -192,16 +192,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                     }
                     InlineAsmOperand::Sym { ref sym } => {
-                        if !self.tcx.features().asm_sym {
-                            feature_err(
-                                &sess.parse_sess,
-                                sym::asm_sym,
-                                *op_sp,
-                                "sym operands for inline assembly are unstable",
-                            )
-                            .emit();
-                        }
-
                         let static_def_id = self
                             .resolver
                             .get_partial_res(sym.id)
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index c6c85ffa84d..21c6a2d26f4 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -1,12 +1,9 @@
-use rustc_errors::{
-    fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay,
-    SubdiagnosticMessage,
-};
+use rustc_errors::DiagnosticArgFromDisplay;
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{symbol::Ident, Span, Symbol};
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::generic_type_with_parentheses, code = "E0214")]
+#[diag(ast_lowering_generic_type_with_parentheses, code = "E0214")]
 pub struct GenericTypeWithParentheses {
     #[primary_span]
     #[label]
@@ -15,27 +12,17 @@ pub struct GenericTypeWithParentheses {
     pub sub: Option<UseAngleBrackets>,
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Subdiagnostic)]
+#[multipart_suggestion(ast_lowering_use_angle_brackets, applicability = "maybe-incorrect")]
 pub struct UseAngleBrackets {
+    #[suggestion_part(code = "<")]
     pub open_param: Span,
+    #[suggestion_part(code = ">")]
     pub close_param: Span,
 }
 
-impl AddToDiagnostic for UseAngleBrackets {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        diag.multipart_suggestion(
-            fluent::ast_lowering::use_angle_brackets,
-            vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))],
-            Applicability::MaybeIncorrect,
-        );
-    }
-}
-
 #[derive(Diagnostic)]
-#[diag(ast_lowering::invalid_abi, code = "E0703")]
+#[diag(ast_lowering_invalid_abi, code = "E0703")]
 #[note]
 pub struct InvalidAbi {
     #[primary_span]
@@ -49,7 +36,7 @@ pub struct InvalidAbi {
 
 #[derive(Subdiagnostic)]
 #[suggestion(
-    ast_lowering::invalid_abi_suggestion,
+    ast_lowering_invalid_abi_suggestion,
     code = "{suggestion}",
     applicability = "maybe-incorrect"
 )]
@@ -60,7 +47,7 @@ pub struct InvalidAbiSuggestion {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::assoc_ty_parentheses)]
+#[diag(ast_lowering_assoc_ty_parentheses)]
 pub struct AssocTyParentheses {
     #[primary_span]
     pub span: Span,
@@ -68,34 +55,24 @@ pub struct AssocTyParentheses {
     pub sub: AssocTyParenthesesSub,
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Subdiagnostic)]
 pub enum AssocTyParenthesesSub {
-    Empty { parentheses_span: Span },
-    NotEmpty { open_param: Span, close_param: Span },
-}
-
-impl AddToDiagnostic for AssocTyParenthesesSub {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        match self {
-            Self::Empty { parentheses_span } => diag.multipart_suggestion(
-                fluent::ast_lowering::remove_parentheses,
-                vec![(parentheses_span, String::new())],
-                Applicability::MaybeIncorrect,
-            ),
-            Self::NotEmpty { open_param, close_param } => diag.multipart_suggestion(
-                fluent::ast_lowering::use_angle_brackets,
-                vec![(open_param, String::from("<")), (close_param, String::from(">"))],
-                Applicability::MaybeIncorrect,
-            ),
-        };
-    }
+    #[multipart_suggestion(ast_lowering_remove_parentheses)]
+    Empty {
+        #[suggestion_part(code = "")]
+        parentheses_span: Span,
+    },
+    #[multipart_suggestion(ast_lowering_use_angle_brackets)]
+    NotEmpty {
+        #[suggestion_part(code = "<")]
+        open_param: Span,
+        #[suggestion_part(code = ">")]
+        close_param: Span,
+    },
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_lowering::misplaced_impl_trait, code = "E0562")]
+#[diag(ast_lowering_misplaced_impl_trait, code = "E0562")]
 pub struct MisplacedImplTrait<'a> {
     #[primary_span]
     pub span: Span,
@@ -103,14 +80,14 @@ pub struct MisplacedImplTrait<'a> {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::rustc_box_attribute_error)]
+#[diag(ast_lowering_rustc_box_attribute_error)]
 pub struct RustcBoxAttributeError {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::underscore_expr_lhs_assign)]
+#[diag(ast_lowering_underscore_expr_lhs_assign)]
 pub struct UnderscoreExprLhsAssign {
     #[primary_span]
     #[label]
@@ -118,7 +95,7 @@ pub struct UnderscoreExprLhsAssign {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::base_expression_double_dot)]
+#[diag(ast_lowering_base_expression_double_dot)]
 pub struct BaseExpressionDoubleDot {
     #[primary_span]
     #[label]
@@ -126,24 +103,24 @@ pub struct BaseExpressionDoubleDot {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::await_only_in_async_fn_and_blocks, code = "E0728")]
+#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = "E0728")]
 pub struct AwaitOnlyInAsyncFnAndBlocks {
     #[primary_span]
     #[label]
     pub dot_await_span: Span,
-    #[label(ast_lowering::this_not_async)]
+    #[label(ast_lowering_this_not_async)]
     pub item_span: Option<Span>,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::generator_too_many_parameters, code = "E0628")]
+#[diag(ast_lowering_generator_too_many_parameters, code = "E0628")]
 pub struct GeneratorTooManyParameters {
     #[primary_span]
     pub fn_decl_span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::closure_cannot_be_static, code = "E0697")]
+#[diag(ast_lowering_closure_cannot_be_static, code = "E0697")]
 pub struct ClosureCannotBeStatic {
     #[primary_span]
     pub fn_decl_span: Span,
@@ -151,14 +128,14 @@ pub struct ClosureCannotBeStatic {
 
 #[derive(Diagnostic, Clone, Copy)]
 #[help]
-#[diag(ast_lowering::async_non_move_closure_not_supported, code = "E0708")]
+#[diag(ast_lowering_async_non_move_closure_not_supported, code = "E0708")]
 pub struct AsyncNonMoveClosureNotSupported {
     #[primary_span]
     pub fn_decl_span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::functional_record_update_destructuring_assignment)]
+#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
 pub struct FunctionalRecordUpdateDestructuringAssignemnt {
     #[primary_span]
     #[suggestion(code = "", applicability = "machine-applicable")]
@@ -166,28 +143,28 @@ pub struct FunctionalRecordUpdateDestructuringAssignemnt {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::async_generators_not_supported, code = "E0727")]
+#[diag(ast_lowering_async_generators_not_supported, code = "E0727")]
 pub struct AsyncGeneratorsNotSupported {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::inline_asm_unsupported_target, code = "E0472")]
+#[diag(ast_lowering_inline_asm_unsupported_target, code = "E0472")]
 pub struct InlineAsmUnsupportedTarget {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::att_syntax_only_x86)]
+#[diag(ast_lowering_att_syntax_only_x86)]
 pub struct AttSyntaxOnlyX86 {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::abi_specified_multiple_times)]
+#[diag(ast_lowering_abi_specified_multiple_times)]
 pub struct AbiSpecifiedMultipleTimes {
     #[primary_span]
     pub abi_span: Span,
@@ -199,7 +176,7 @@ pub struct AbiSpecifiedMultipleTimes {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::clobber_abi_not_supported)]
+#[diag(ast_lowering_clobber_abi_not_supported)]
 pub struct ClobberAbiNotSupported {
     #[primary_span]
     pub abi_span: Span,
@@ -207,7 +184,7 @@ pub struct ClobberAbiNotSupported {
 
 #[derive(Diagnostic)]
 #[note]
-#[diag(ast_lowering::invalid_abi_clobber_abi)]
+#[diag(ast_lowering_invalid_abi_clobber_abi)]
 pub struct InvalidAbiClobberAbi {
     #[primary_span]
     pub abi_span: Span,
@@ -215,7 +192,7 @@ pub struct InvalidAbiClobberAbi {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::invalid_register)]
+#[diag(ast_lowering_invalid_register)]
 pub struct InvalidRegister<'a> {
     #[primary_span]
     pub op_span: Span,
@@ -224,7 +201,7 @@ pub struct InvalidRegister<'a> {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::invalid_register_class)]
+#[diag(ast_lowering_invalid_register_class)]
 pub struct InvalidRegisterClass<'a> {
     #[primary_span]
     pub op_span: Span,
@@ -233,12 +210,12 @@ pub struct InvalidRegisterClass<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_lowering::invalid_asm_template_modifier_reg_class)]
+#[diag(ast_lowering_invalid_asm_template_modifier_reg_class)]
 pub struct InvalidAsmTemplateModifierRegClass {
     #[primary_span]
-    #[label(ast_lowering::template_modifier)]
+    #[label(ast_lowering_template_modifier)]
     pub placeholder_span: Span,
-    #[label(ast_lowering::argument)]
+    #[label(ast_lowering_argument)]
     pub op_span: Span,
     #[subdiagnostic]
     pub sub: InvalidAsmTemplateModifierRegClassSub,
@@ -246,34 +223,34 @@ pub struct InvalidAsmTemplateModifierRegClass {
 
 #[derive(Subdiagnostic)]
 pub enum InvalidAsmTemplateModifierRegClassSub {
-    #[note(ast_lowering::support_modifiers)]
+    #[note(ast_lowering_support_modifiers)]
     SupportModifier { class_name: Symbol, modifiers: String },
-    #[note(ast_lowering::does_not_support_modifiers)]
+    #[note(ast_lowering_does_not_support_modifiers)]
     DoesNotSupportModifier { class_name: Symbol },
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::invalid_asm_template_modifier_const)]
+#[diag(ast_lowering_invalid_asm_template_modifier_const)]
 pub struct InvalidAsmTemplateModifierConst {
     #[primary_span]
-    #[label(ast_lowering::template_modifier)]
+    #[label(ast_lowering_template_modifier)]
     pub placeholder_span: Span,
-    #[label(ast_lowering::argument)]
+    #[label(ast_lowering_argument)]
     pub op_span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::invalid_asm_template_modifier_sym)]
+#[diag(ast_lowering_invalid_asm_template_modifier_sym)]
 pub struct InvalidAsmTemplateModifierSym {
     #[primary_span]
-    #[label(ast_lowering::template_modifier)]
+    #[label(ast_lowering_template_modifier)]
     pub placeholder_span: Span,
-    #[label(ast_lowering::argument)]
+    #[label(ast_lowering_argument)]
     pub op_span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::register_class_only_clobber)]
+#[diag(ast_lowering_register_class_only_clobber)]
 pub struct RegisterClassOnlyClobber {
     #[primary_span]
     pub op_span: Span,
@@ -281,12 +258,12 @@ pub struct RegisterClassOnlyClobber {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::register_conflict)]
+#[diag(ast_lowering_register_conflict)]
 pub struct RegisterConflict<'a> {
     #[primary_span]
-    #[label(ast_lowering::register1)]
+    #[label(ast_lowering_register1)]
     pub op_span1: Span,
-    #[label(ast_lowering::register2)]
+    #[label(ast_lowering_register2)]
     pub op_span2: Span,
     pub reg1_name: &'a str,
     pub reg2_name: &'a str,
@@ -296,12 +273,13 @@ pub struct RegisterConflict<'a> {
 
 #[derive(Diagnostic, Clone, Copy)]
 #[help]
-#[diag(ast_lowering::sub_tuple_binding)]
+#[diag(ast_lowering_sub_tuple_binding)]
 pub struct SubTupleBinding<'a> {
     #[primary_span]
     #[label]
-    #[suggestion_verbose(
-        ast_lowering::sub_tuple_binding_suggestion,
+    #[suggestion(
+        ast_lowering_sub_tuple_binding_suggestion,
+        style = "verbose",
         code = "..",
         applicability = "maybe-incorrect"
     )]
@@ -312,56 +290,56 @@ pub struct SubTupleBinding<'a> {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::extra_double_dot)]
+#[diag(ast_lowering_extra_double_dot)]
 pub struct ExtraDoubleDot<'a> {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(ast_lowering::previously_used_here)]
+    #[label(ast_lowering_previously_used_here)]
     pub prev_span: Span,
     pub ctx: &'a str,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
 #[note]
-#[diag(ast_lowering::misplaced_double_dot)]
+#[diag(ast_lowering_misplaced_double_dot)]
 pub struct MisplacedDoubleDot {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::misplaced_relax_trait_bound)]
+#[diag(ast_lowering_misplaced_relax_trait_bound)]
 pub struct MisplacedRelaxTraitBound {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::not_supported_for_lifetime_binder_async_closure)]
+#[diag(ast_lowering_not_supported_for_lifetime_binder_async_closure)]
 pub struct NotSupportedForLifetimeBinderAsyncClosure {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::arbitrary_expression_in_pattern)]
+#[diag(ast_lowering_arbitrary_expression_in_pattern)]
 pub struct ArbitraryExpressionInPattern {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::inclusive_range_with_no_end)]
+#[diag(ast_lowering_inclusive_range_with_no_end)]
 pub struct InclusiveRangeWithNoEnd {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::trait_fn_async, code = "E0706")]
+#[diag(ast_lowering_trait_fn_async, code = "E0706")]
 #[note]
-#[note(ast_lowering::note2)]
+#[note(note2)]
 pub struct TraitFnAsync {
     #[primary_span]
     pub fn_span: Span,
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index c55b4906302..ec9c3935020 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -387,32 +387,58 @@ impl<'hir> LoweringContext<'_, 'hir> {
         then: &Block,
         else_opt: Option<&Expr>,
     ) -> hir::ExprKind<'hir> {
-        let lowered_cond = self.lower_expr(cond);
-        let new_cond = self.manage_let_cond(lowered_cond);
+        let lowered_cond = self.lower_cond(cond);
         let then_expr = self.lower_block_expr(then);
         if let Some(rslt) = else_opt {
-            hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), Some(self.lower_expr(rslt)))
+            hir::ExprKind::If(
+                lowered_cond,
+                self.arena.alloc(then_expr),
+                Some(self.lower_expr(rslt)),
+            )
         } else {
-            hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), None)
+            hir::ExprKind::If(lowered_cond, self.arena.alloc(then_expr), None)
         }
     }
 
-    // If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond`
-    // in a temporary block.
-    fn manage_let_cond(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> {
-        fn has_let_expr<'hir>(expr: &'hir hir::Expr<'hir>) -> bool {
-            match expr.kind {
-                hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
-                hir::ExprKind::Let(..) => true,
+    // Lowers a condition (i.e. `cond` in `if cond` or `while cond`), wrapping it in a terminating scope
+    // so that temporaries created in the condition don't live beyond it.
+    fn lower_cond(&mut self, cond: &Expr) -> &'hir hir::Expr<'hir> {
+        fn has_let_expr(expr: &Expr) -> bool {
+            match &expr.kind {
+                ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
+                ExprKind::Let(..) => true,
                 _ => false,
             }
         }
-        if has_let_expr(cond) {
-            cond
-        } else {
-            let reason = DesugaringKind::CondTemporary;
-            let span_block = self.mark_span_with_reason(reason, cond.span, None);
-            self.expr_drop_temps(span_block, cond, AttrVec::new())
+
+        // We have to take special care for `let` exprs in the condition, e.g. in
+        // `if let pat = val` or `if foo && let pat = val`, as we _do_ want `val` to live beyond the
+        // condition in this case.
+        //
+        // In order to mantain the drop behavior for the non `let` parts of the condition,
+        // we still wrap them in terminating scopes, e.g. `if foo && let pat = val` essentially
+        // gets transformed into `if { let _t = foo; _t } && let pat = val`
+        match &cond.kind {
+            ExprKind::Binary(op @ Spanned { node: ast::BinOpKind::And, .. }, lhs, rhs)
+                if has_let_expr(cond) =>
+            {
+                let op = self.lower_binop(*op);
+                let lhs = self.lower_cond(lhs);
+                let rhs = self.lower_cond(rhs);
+
+                self.arena.alloc(self.expr(
+                    cond.span,
+                    hir::ExprKind::Binary(op, lhs, rhs),
+                    AttrVec::new(),
+                ))
+            }
+            ExprKind::Let(..) => self.lower_expr(cond),
+            _ => {
+                let cond = self.lower_expr(cond);
+                let reason = DesugaringKind::CondTemporary;
+                let span_block = self.mark_span_with_reason(reason, cond.span, None);
+                self.expr_drop_temps(span_block, cond, AttrVec::new())
+            }
         }
     }
 
@@ -439,14 +465,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
         body: &Block,
         opt_label: Option<Label>,
     ) -> hir::ExprKind<'hir> {
-        let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond));
-        let new_cond = self.manage_let_cond(lowered_cond);
+        let lowered_cond = self.with_loop_condition_scope(|t| t.lower_cond(cond));
         let then = self.lower_block_expr(body);
         let expr_break = self.expr_break(span, AttrVec::new());
         let stmt_break = self.stmt_expr(span, expr_break);
         let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);
         let else_expr = self.arena.alloc(self.expr_block(else_blk, AttrVec::new()));
-        let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr));
+        let if_kind = hir::ExprKind::If(lowered_cond, self.arena.alloc(then), Some(else_expr));
         let if_expr = self.expr(span, if_kind, AttrVec::new());
         let block = self.block_expr(self.arena.alloc(if_expr));
         let span = self.lower_span(span.with_hi(cond.span.hi()));
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 6d716796343..f1851d7b40e 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -112,19 +112,19 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
 
     fn visit_nested_item(&mut self, item: ItemId) {
         debug!("visit_nested_item: {:?}", item);
-        self.insert_nested(item.def_id.def_id);
+        self.insert_nested(item.owner_id.def_id);
     }
 
     fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
-        self.insert_nested(item_id.def_id.def_id);
+        self.insert_nested(item_id.owner_id.def_id);
     }
 
     fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
-        self.insert_nested(item_id.def_id.def_id);
+        self.insert_nested(item_id.owner_id.def_id);
     }
 
     fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
-        self.insert_nested(foreign_id.def_id.def_id);
+        self.insert_nested(foreign_id.owner_id.def_id);
     }
 
     fn visit_nested_body(&mut self, id: BodyId) {
@@ -143,7 +143,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
 
     #[instrument(level = "debug", skip(self))]
     fn visit_item(&mut self, i: &'hir Item<'hir>) {
-        debug_assert_eq!(i.def_id, self.owner);
+        debug_assert_eq!(i.owner_id, self.owner);
         self.with_parent(i.hir_id(), |this| {
             if let ItemKind::Struct(ref struct_def, _) = i.kind {
                 // If this is a tuple or unit-like struct, register the constructor.
@@ -157,7 +157,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
 
     #[instrument(level = "debug", skip(self))]
     fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
-        debug_assert_eq!(fi.def_id, self.owner);
+        debug_assert_eq!(fi.owner_id, self.owner);
         self.with_parent(fi.hir_id(), |this| {
             intravisit::walk_foreign_item(this, fi);
         });
@@ -176,7 +176,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
 
     #[instrument(level = "debug", skip(self))]
     fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
-        debug_assert_eq!(ti.def_id, self.owner);
+        debug_assert_eq!(ti.owner_id, self.owner);
         self.with_parent(ti.hir_id(), |this| {
             intravisit::walk_trait_item(this, ti);
         });
@@ -184,7 +184,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
 
     #[instrument(level = "debug", skip(self))]
     fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
-        debug_assert_eq!(ii.def_id, self.owner);
+        debug_assert_eq!(ii.owner_id, self.owner);
         self.with_parent(ii.hir_id(), |this| {
             intravisit::walk_impl_item(this, ii);
         });
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 687d810ed4e..76316a574ac 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -178,7 +178,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
         let mut node_ids =
-            smallvec![hir::ItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }];
+            smallvec![hir::ItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }];
         if let ItemKind::Use(ref use_tree) = &i.kind {
             self.lower_item_id_use_tree(use_tree, i.id, &mut node_ids);
         }
@@ -195,7 +195,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             UseTreeKind::Nested(ref nested_vec) => {
                 for &(ref nested, id) in nested_vec {
                     vec.push(hir::ItemId {
-                        def_id: hir::OwnerId { def_id: self.local_def_id(id) },
+                        owner_id: hir::OwnerId { def_id: self.local_def_id(id) },
                     });
                     self.lower_item_id_use_tree(nested, id, vec);
                 }
@@ -206,7 +206,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2])
                 {
                     vec.push(hir::ItemId {
-                        def_id: hir::OwnerId { def_id: self.local_def_id(id) },
+                        owner_id: hir::OwnerId { def_id: self.local_def_id(id) },
                     });
                 }
             }
@@ -220,7 +220,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let attrs = self.lower_attrs(hir_id, &i.attrs);
         let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind);
         let item = hir::Item {
-            def_id: hir_id.expect_owner(),
+            owner_id: hir_id.expect_owner(),
             ident: self.lower_ident(ident),
             kind,
             vis_span,
@@ -545,7 +545,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let ident = *ident;
                     let mut path = path.clone();
                     for seg in &mut path.segments {
-                        seg.id = self.next_node_id();
+                        // Give the cloned segment the same resolution information
+                        // as the old one (this is needed for stability checking).
+                        let new_id = self.next_node_id();
+                        self.resolver.clone_res(seg.id, new_id);
+                        seg.id = new_id;
                     }
                     let span = path.span;
 
@@ -558,7 +562,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         }
 
                         let item = hir::Item {
-                            def_id: hir::OwnerId { def_id: new_id },
+                            owner_id: hir::OwnerId { def_id: new_id },
                             ident: this.lower_ident(ident),
                             kind,
                             vis_span,
@@ -614,7 +618,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
                     // Give the segments new node-ids since they are being cloned.
                     for seg in &mut prefix.segments {
-                        seg.id = self.next_node_id();
+                        // Give the cloned segment the same resolution information
+                        // as the old one (this is needed for stability checking).
+                        let new_id = self.next_node_id();
+                        self.resolver.clone_res(seg.id, new_id);
+                        seg.id = new_id;
                     }
 
                     // Each `use` import is an item and thus are owners of the
@@ -632,7 +640,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         }
 
                         let item = hir::Item {
-                            def_id: hir::OwnerId { def_id: new_hir_id },
+                            owner_id: hir::OwnerId { def_id: new_hir_id },
                             ident: this.lower_ident(ident),
                             kind,
                             vis_span,
@@ -652,10 +660,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> {
         let hir_id = self.lower_node_id(i.id);
-        let def_id = hir_id.expect_owner();
+        let owner_id = hir_id.expect_owner();
         self.lower_attrs(hir_id, &i.attrs);
         let item = hir::ForeignItem {
-            def_id,
+            owner_id,
             ident: self.lower_ident(i.ident),
             kind: match i.kind {
                 ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
@@ -694,7 +702,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef {
         hir::ForeignItemRef {
-            id: hir::ForeignItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
+            id: hir::ForeignItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
         }
@@ -837,7 +845,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         self.lower_attrs(hir_id, &i.attrs);
         let item = hir::TraitItem {
-            def_id: trait_item_def_id,
+            owner_id: trait_item_def_id,
             ident: self.lower_ident(i.ident),
             generics,
             kind,
@@ -856,7 +864,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
             AssocItemKind::MacCall(..) => unimplemented!(),
         };
-        let id = hir::TraitItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
+        let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
         hir::TraitItemRef {
             id,
             ident: self.lower_ident(i.ident),
@@ -923,7 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let hir_id = self.lower_node_id(i.id);
         self.lower_attrs(hir_id, &i.attrs);
         let item = hir::ImplItem {
-            def_id: hir_id.expect_owner(),
+            owner_id: hir_id.expect_owner(),
             ident: self.lower_ident(i.ident),
             generics,
             kind,
@@ -936,7 +944,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
         hir::ImplItemRef {
-            id: hir::ImplItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
+            id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
             kind: match &i.kind {
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index ce5893efa92..ff29d15f1b5 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -160,6 +160,10 @@ trait ResolverAstLoweringExt {
     fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
     fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
     fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
+    // Clones the resolution (if any) on 'source' and applies it
+    // to 'target'. Used when desugaring a `UseTreeKind::Nested` to
+    // multiple `UseTreeKind::Simple`s
+    fn clone_res(&mut self, source: NodeId, target: NodeId);
     fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
     fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
     fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
@@ -192,6 +196,12 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
         None
     }
 
+    fn clone_res(&mut self, source: NodeId, target: NodeId) {
+        if let Some(res) = self.partial_res_map.get(&source) {
+            self.partial_res_map.insert(target, *res);
+        }
+    }
+
     /// Obtains resolution for a `NodeId` with a single resolution.
     fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
         self.partial_res_map.get(&id).copied()
@@ -497,6 +507,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
+    /// resolver (if any).
+    fn orig_opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
+        self.resolver.node_id_to_def_id.get(&node).map(|local_def_id| *local_def_id)
+    }
+
+    fn orig_local_def_id(&self, node: NodeId) -> LocalDefId {
+        self.orig_opt_local_def_id(node)
+            .unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+    }
+
+    /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
     /// resolver (if any), after applying any remapping from `get_remapped_def_id`.
     ///
     /// For example, in a function like `fn foo<'a>(x: &'a u32)`,
@@ -510,10 +531,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// we would create an opaque type `type FooReturn<'a1> = impl Debug + 'a1`.
     /// When lowering the `Debug + 'a` bounds, we add a remapping to map `'a` to `'a1`.
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
-        self.resolver
-            .node_id_to_def_id
-            .get(&node)
-            .map(|local_def_id| self.get_remapped_def_id(*local_def_id))
+        self.orig_opt_local_def_id(node).map(|local_def_id| self.get_remapped_def_id(local_def_id))
     }
 
     fn local_def_id(&self, node: NodeId) -> LocalDefId {
@@ -522,9 +540,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
     /// Get the previously recorded `to` local def id given the `from` local def id, obtained using
     /// `generics_def_id_map` field.
-    fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId {
+    fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId {
         // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we
-        // push new mappings so we need to try first the latest mappings, hence `iter().rev()`.
+        // push new mappings, so we first need to get the latest (innermost) mappings, hence `iter().rev()`.
         //
         // Consider:
         //
@@ -534,18 +552,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         //
         // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]`
         //
-        // for the opaque type generated on `impl Sized + 'b`, We want the result to be:
-        // impl_sized#'b, so iterating forward is the wrong thing to do.
-        for map in self.generics_def_id_map.iter().rev() {
-            if let Some(r) = map.get(&local_def_id) {
-                debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`");
-                local_def_id = *r;
-            } else {
-                debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map");
-            }
-        }
-
-        local_def_id
+        // for the opaque type generated on `impl Sized + 'b`, we want the result to be: impl_sized#'b.
+        // So, if we were trying to find first from the start (outermost) would give the wrong result, impl_trait#'b.
+        self.generics_def_id_map
+            .iter()
+            .rev()
+            .find_map(|map| map.get(&local_def_id).map(|local_def_id| *local_def_id))
+            .unwrap_or(local_def_id)
     }
 
     /// Freshen the `LoweringContext` and ready it to lower a nested item.
@@ -1561,7 +1574,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
         hir::TyKind::OpaqueDef(
-            hir::ItemId { def_id: hir::OwnerId { def_id: opaque_ty_def_id } },
+            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
             lifetimes,
             in_trait,
         )
@@ -1580,7 +1593,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // Generate an `type Foo = impl Trait;` declaration.
         trace!("registering opaque type with id {:#?}", opaque_ty_id);
         let opaque_ty_item = hir::Item {
-            def_id: hir::OwnerId { def_id: opaque_ty_id },
+            owner_id: hir::OwnerId { def_id: opaque_ty_id },
             ident: Ident::empty(),
             kind: opaque_ty_item_kind,
             vis_span: self.lower_span(span.shrink_to_lo()),
@@ -1623,7 +1636,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                 LifetimeRes::Fresh { param, binder: _ } => {
                     debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
-                    if let Some(old_def_id) = self.opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
+                    if let Some(old_def_id) = self.orig_opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
                         let node_id = self.next_node_id();
 
                         let new_def_id = self.create_def(
@@ -1868,7 +1881,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
         debug!(?extra_lifetime_params);
         for (ident, outer_node_id, outer_res) in extra_lifetime_params {
-            let outer_def_id = self.local_def_id(outer_node_id);
+            let outer_def_id = self.orig_local_def_id(outer_node_id);
             let inner_node_id = self.next_node_id();
 
             // Add a definition for the in scope lifetime def.
@@ -2031,7 +2044,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // async fn, so the *type parameters* are inherited.  It's
         // only the lifetime parameters that we must supply.
         let opaque_ty_ref = hir::TyKind::OpaqueDef(
-            hir::ItemId { def_id: hir::OwnerId { def_id: opaque_ty_def_id } },
+            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
             generic_args,
             in_trait,
         );
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 888776cccac..c6955741fd4 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -191,7 +191,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
                 }
                 GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
-                    ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
+                    ParenthesizedGenericArgs::Ok => {
+                        self.lower_parenthesized_parameter_data(data, itctx)
+                    }
                     ParenthesizedGenericArgs::Err => {
                         // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
                         let sub = if !data.inputs.is_empty() {
@@ -344,6 +346,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_parenthesized_parameter_data(
         &mut self,
         data: &ParenthesizedArgs,
+        itctx: &ImplTraitContext,
     ) -> (GenericArgsCtor<'hir>, bool) {
         // Switch to `PassThrough` mode for anonymous lifetimes; this
         // means that we permit things like `&Ref<T>`, where `Ref` has
@@ -355,6 +358,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             self.lower_ty_direct(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
         }));
         let output_ty = match output {
+            // Only allow `impl Trait` in return position. i.e.:
+            // ```rust
+            // fn f(_: impl Fn() -> impl Debug) -> impl Fn() -> impl Debug
+            // //      disallowed --^^^^^^^^^^        allowed --^^^^^^^^^^
+            // ```
+            FnRetTy::Ty(ty)
+                if matches!(itctx, ImplTraitContext::ReturnPositionOpaqueTy { .. })
+                    && self.tcx.features().impl_trait_in_fn_trait_return =>
+            {
+                self.lower_ty(&ty, itctx)
+            }
             FnRetTy::Ty(ty) => {
                 self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
             }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 1a4c60087c3..03664324404 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -14,6 +14,7 @@ use rustc_ast::*;
 use rustc_ast_pretty::pprust::{self, State};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability};
+use rustc_macros::Subdiagnostic;
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::{
     DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -38,6 +39,13 @@ enum SelfSemantic {
     No,
 }
 
+/// What is the context that prevents using `~const`?
+enum DisallowTildeConstContext<'a> {
+    TraitObject,
+    ImplTrait,
+    Fn(FnKind<'a>),
+}
+
 struct AstValidator<'a> {
     session: &'a Session,
 
@@ -56,7 +64,7 @@ struct AstValidator<'a> {
     /// e.g., `impl Iterator<Item = impl Debug>`.
     outer_impl_trait: Option<Span>,
 
-    is_tilde_const_allowed: bool,
+    disallow_tilde_const: Option<DisallowTildeConstContext<'a>>,
 
     /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
     /// or `Foo::Bar<impl Trait>`
@@ -93,18 +101,26 @@ impl<'a> AstValidator<'a> {
         self.is_impl_trait_banned = old;
     }
 
-    fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.is_tilde_const_allowed, allowed);
+    fn with_tilde_const(
+        &mut self,
+        disallowed: Option<DisallowTildeConstContext<'a>>,
+        f: impl FnOnce(&mut Self),
+    ) {
+        let old = mem::replace(&mut self.disallow_tilde_const, disallowed);
         f(self);
-        self.is_tilde_const_allowed = old;
+        self.disallow_tilde_const = old;
     }
 
     fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
-        self.with_tilde_const(true, f)
+        self.with_tilde_const(None, f)
     }
 
-    fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
-        self.with_tilde_const(false, f)
+    fn with_banned_tilde_const(
+        &mut self,
+        ctx: DisallowTildeConstContext<'a>,
+        f: impl FnOnce(&mut Self),
+    ) {
+        self.with_tilde_const(Some(ctx), f)
     }
 
     fn with_let_management(
@@ -154,7 +170,7 @@ impl<'a> AstValidator<'a> {
                 DEPRECATED_WHERE_CLAUSE_LOCATION,
                 id,
                 where_clauses.0.1,
-                fluent::ast_passes::deprecated_where_clause_location,
+                fluent::ast_passes_deprecated_where_clause_location,
                 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
                     where_clauses.1.1.shrink_to_hi(),
                     suggestion,
@@ -172,7 +188,7 @@ impl<'a> AstValidator<'a> {
     fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
         let old = mem::replace(&mut self.outer_impl_trait, outer);
         if outer.is_some() {
-            self.with_banned_tilde_const(f);
+            self.with_banned_tilde_const(DisallowTildeConstContext::ImplTrait, f);
         } else {
             f(self);
         }
@@ -197,7 +213,10 @@ impl<'a> AstValidator<'a> {
             TyKind::ImplTrait(..) => {
                 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
             }
-            TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
+            TyKind::TraitObject(..) => self
+                .with_banned_tilde_const(DisallowTildeConstContext::TraitObject, |this| {
+                    visit::walk_ty(this, t)
+                }),
             TyKind::Path(ref qself, ref path) => {
                 // We allow these:
                 //  - `Option<impl Trait>`
@@ -233,20 +252,6 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
-        if let Some(ident) = field.ident {
-            if ident.name == kw::Underscore {
-                self.visit_vis(&field.vis);
-                self.visit_ident(ident);
-                self.visit_ty_common(&field.ty);
-                self.walk_ty(&field.ty);
-                walk_list!(self, visit_attribute, &field.attrs);
-                return;
-            }
-        }
-        self.visit_field_def(field);
-    }
-
     fn err_handler(&self) -> &rustc_errors::Handler {
         &self.session.diagnostic()
     }
@@ -987,8 +992,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         visit::walk_lifetime(self, lifetime);
     }
 
-    fn visit_field_def(&mut self, s: &'a FieldDef) {
-        visit::walk_field_def(self, s)
+    fn visit_field_def(&mut self, field: &'a FieldDef) {
+        visit::walk_field_def(self, field)
     }
 
     fn visit_item(&mut self, item: &'a Item) {
@@ -1176,42 +1181,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     self.check_mod_file_item_asciionly(item.ident);
                 }
             }
-            ItemKind::Struct(ref vdata, ref generics) => match vdata {
-                // Duplicating the `Visitor` logic allows catching all cases
-                // of `Anonymous(Struct, Union)` outside of a field struct or union.
-                //
-                // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
-                // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
-                // it uses `visit_ty_common`, which doesn't contain that specific check.
-                VariantData::Struct(ref fields, ..) => {
-                    self.visit_vis(&item.vis);
-                    self.visit_ident(item.ident);
-                    self.visit_generics(generics);
-                    self.with_banned_assoc_ty_bound(|this| {
-                        walk_list!(this, visit_struct_field_def, fields);
-                    });
-                    walk_list!(self, visit_attribute, &item.attrs);
-                    return;
-                }
-                _ => {}
-            },
-            ItemKind::Union(ref vdata, ref generics) => {
+            ItemKind::Union(ref vdata, ..) => {
                 if vdata.fields().is_empty() {
                     self.err_handler().span_err(item.span, "unions cannot have zero fields");
                 }
-                match vdata {
-                    VariantData::Struct(ref fields, ..) => {
-                        self.visit_vis(&item.vis);
-                        self.visit_ident(item.ident);
-                        self.visit_generics(generics);
-                        self.with_banned_assoc_ty_bound(|this| {
-                            walk_list!(this, visit_struct_field_def, fields);
-                        });
-                        walk_list!(self, visit_attribute, &item.attrs);
-                        return;
-                    }
-                    _ => {}
-                }
             }
             ItemKind::Const(def, .., None) => {
                 self.check_defaultness(item.span, def);
@@ -1411,13 +1384,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     );
                     err.emit();
                 }
-                (_, TraitBoundModifier::MaybeConst) => {
-                    if !self.is_tilde_const_allowed {
-                        self.err_handler()
-                            .struct_span_err(bound.span(), "`~const` is not allowed here")
-                            .note("only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions")
-                            .emit();
-                    }
+                (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
+                    let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
+                    match reason {
+                        DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
+                        DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"),
+                        DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
+                        DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
+                    };
+                    err.emit();
                 }
                 (_, TraitBoundModifier::MaybeConstMaybe) => {
                     self.err_handler()
@@ -1523,10 +1498,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             });
         }
 
-        let tilde_const_allowed = matches!(fk.header(), Some(FnHeader { .. }))
-            || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
+        let tilde_const_allowed =
+            matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
+                || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
+
+        let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
 
-        self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk));
+        self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
     }
 
     fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
@@ -1770,7 +1748,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
         in_const_trait_impl: false,
         has_proc_macro_decls: false,
         outer_impl_trait: None,
-        is_tilde_const_allowed: false,
+        disallow_tilde_const: None,
         is_impl_trait_banned: false,
         is_assoc_ty_bound_banned: false,
         forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
@@ -1782,15 +1760,17 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
 }
 
 /// Used to forbid `let` expressions in certain syntactic locations.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Subdiagnostic)]
 pub(crate) enum ForbiddenLetReason {
     /// `let` is not valid and the source environment is not important
     GenericForbidden,
     /// A let chain with the `||` operator
-    NotSupportedOr(Span),
+    #[note(not_supported_or)]
+    NotSupportedOr(#[primary_span] Span),
     /// A let chain with invalid parentheses
     ///
     /// For example, `let 1 = 1 && (expr && expr)` is allowed
     /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
-    NotSupportedParentheses(Span),
+    #[note(not_supported_parentheses)]
+    NotSupportedParentheses(#[primary_span] Span),
 }
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index ba2ed24fc08..59f582f10d9 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -7,7 +7,7 @@ use rustc_span::{Span, Symbol};
 use crate::ast_validation::ForbiddenLetReason;
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::forbidden_let)]
+#[diag(ast_passes_forbidden_let)]
 #[note]
 pub struct ForbiddenLet {
     #[primary_span]
@@ -16,25 +16,8 @@ pub struct ForbiddenLet {
     pub(crate) reason: ForbiddenLetReason,
 }
 
-impl AddToDiagnostic for ForbiddenLetReason {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        match self {
-            Self::GenericForbidden => {}
-            Self::NotSupportedOr(span) => {
-                diag.span_note(span, fluent::ast_passes::not_supported_or);
-            }
-            Self::NotSupportedParentheses(span) => {
-                diag.span_note(span, fluent::ast_passes::not_supported_parentheses);
-            }
-        }
-    }
-}
-
 #[derive(Diagnostic)]
-#[diag(ast_passes::forbidden_let_stable)]
+#[diag(ast_passes_forbidden_let_stable)]
 #[note]
 pub struct ForbiddenLetStable {
     #[primary_span]
@@ -42,21 +25,21 @@ pub struct ForbiddenLetStable {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::forbidden_assoc_constraint)]
+#[diag(ast_passes_forbidden_assoc_constraint)]
 pub struct ForbiddenAssocConstraint {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::keyword_lifetime)]
+#[diag(ast_passes_keyword_lifetime)]
 pub struct KeywordLifetime {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::invalid_label)]
+#[diag(ast_passes_invalid_label)]
 pub struct InvalidLabel {
     #[primary_span]
     pub span: Span,
@@ -64,11 +47,11 @@ pub struct InvalidLabel {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::invalid_visibility, code = "E0449")]
+#[diag(ast_passes_invalid_visibility, code = "E0449")]
 pub struct InvalidVisibility {
     #[primary_span]
     pub span: Span,
-    #[label(ast_passes::implied)]
+    #[label(implied)]
     pub implied: Option<Span>,
     #[subdiagnostic]
     pub note: Option<InvalidVisibilityNote>,
@@ -76,14 +59,14 @@ pub struct InvalidVisibility {
 
 #[derive(Subdiagnostic)]
 pub enum InvalidVisibilityNote {
-    #[note(ast_passes::individual_impl_items)]
+    #[note(individual_impl_items)]
     IndividualImplItems,
-    #[note(ast_passes::individual_foreign_items)]
+    #[note(individual_foreign_items)]
     IndividualForeignItems,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::trait_fn_const, code = "E0379")]
+#[diag(ast_passes_trait_fn_const, code = "E0379")]
 pub struct TraitFnConst {
     #[primary_span]
     #[label]
@@ -91,21 +74,21 @@ pub struct TraitFnConst {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::forbidden_lifetime_bound)]
+#[diag(ast_passes_forbidden_lifetime_bound)]
 pub struct ForbiddenLifetimeBound {
     #[primary_span]
     pub spans: Vec<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::forbidden_non_lifetime_param)]
+#[diag(ast_passes_forbidden_non_lifetime_param)]
 pub struct ForbiddenNonLifetimeParam {
     #[primary_span]
     pub spans: Vec<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_param_too_many)]
+#[diag(ast_passes_fn_param_too_many)]
 pub struct FnParamTooMany {
     #[primary_span]
     pub span: Span,
@@ -113,21 +96,21 @@ pub struct FnParamTooMany {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_param_c_var_args_only)]
+#[diag(ast_passes_fn_param_c_var_args_only)]
 pub struct FnParamCVarArgsOnly {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_param_c_var_args_not_last)]
+#[diag(ast_passes_fn_param_c_var_args_not_last)]
 pub struct FnParamCVarArgsNotLast {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_param_doc_comment)]
+#[diag(ast_passes_fn_param_doc_comment)]
 pub struct FnParamDocComment {
     #[primary_span]
     #[label]
@@ -135,14 +118,14 @@ pub struct FnParamDocComment {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_param_forbidden_attr)]
+#[diag(ast_passes_fn_param_forbidden_attr)]
 pub struct FnParamForbiddenAttr {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_param_forbidden_self)]
+#[diag(ast_passes_fn_param_forbidden_self)]
 #[note]
 pub struct FnParamForbiddenSelf {
     #[primary_span]
@@ -151,7 +134,7 @@ pub struct FnParamForbiddenSelf {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::forbidden_default)]
+#[diag(ast_passes_forbidden_default)]
 pub struct ForbiddenDefault {
     #[primary_span]
     pub span: Span,
@@ -160,7 +143,7 @@ pub struct ForbiddenDefault {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::assoc_const_without_body)]
+#[diag(ast_passes_assoc_const_without_body)]
 pub struct AssocConstWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -169,7 +152,7 @@ pub struct AssocConstWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::assoc_fn_without_body)]
+#[diag(ast_passes_assoc_fn_without_body)]
 pub struct AssocFnWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -178,7 +161,7 @@ pub struct AssocFnWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::assoc_type_without_body)]
+#[diag(ast_passes_assoc_type_without_body)]
 pub struct AssocTypeWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -187,7 +170,7 @@ pub struct AssocTypeWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::const_without_body)]
+#[diag(ast_passes_const_without_body)]
 pub struct ConstWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -196,7 +179,7 @@ pub struct ConstWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::static_without_body)]
+#[diag(ast_passes_static_without_body)]
 pub struct StaticWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -205,7 +188,7 @@ pub struct StaticWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::ty_alias_without_body)]
+#[diag(ast_passes_ty_alias_without_body)]
 pub struct TyAliasWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -214,7 +197,7 @@ pub struct TyAliasWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_without_body)]
+#[diag(ast_passes_fn_without_body)]
 pub struct FnWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -243,7 +226,7 @@ impl AddToDiagnostic for ExternBlockSuggestion {
         let end_suggestion = " }".to_owned();
 
         diag.multipart_suggestion(
-            fluent::ast_passes::extern_block_suggestion,
+            fluent::extern_block_suggestion,
             vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)],
             Applicability::MaybeIncorrect,
         );
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 0f11c176652..546010135a7 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -1,7 +1,7 @@
 use rustc_ast as ast;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
-use rustc_ast::{PatKind, RangeEnd, VariantData};
+use rustc_ast::{PatKind, RangeEnd};
 use rustc_errors::{struct_span_err, Applicability, StashKey};
 use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
 use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
@@ -116,46 +116,6 @@ impl<'a> PostExpansionVisitor<'a> {
         }
     }
 
-    fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) {
-        let has_fields = variants.iter().any(|variant| match variant.data {
-            VariantData::Tuple(..) | VariantData::Struct(..) => true,
-            VariantData::Unit(..) => false,
-        });
-
-        let discriminant_spans = variants
-            .iter()
-            .filter(|variant| match variant.data {
-                VariantData::Tuple(..) | VariantData::Struct(..) => false,
-                VariantData::Unit(..) => true,
-            })
-            .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
-            .collect::<Vec<_>>();
-
-        if !discriminant_spans.is_empty() && has_fields {
-            let mut err = feature_err(
-                &self.sess.parse_sess,
-                sym::arbitrary_enum_discriminant,
-                discriminant_spans.clone(),
-                "custom discriminant values are not allowed in enums with tuple or struct variants",
-            );
-            for sp in discriminant_spans {
-                err.span_label(sp, "disallowed custom discriminant");
-            }
-            for variant in variants.iter() {
-                match &variant.data {
-                    VariantData::Struct(..) => {
-                        err.span_label(variant.span, "struct variant defined here");
-                    }
-                    VariantData::Tuple(..) => {
-                        err.span_label(variant.span, "tuple variant defined here");
-                    }
-                    VariantData::Unit(..) => {}
-                }
-            }
-            err.emit();
-        }
-    }
-
     /// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
     fn check_impl_trait(&self, ty: &ast::Ty) {
         struct ImplTraitVisitor<'a> {
@@ -273,26 +233,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 }
             }
 
-            ast::ItemKind::Enum(ast::EnumDef { ref variants, .. }, ..) => {
-                for variant in variants {
-                    match (&variant.data, &variant.disr_expr) {
-                        (ast::VariantData::Unit(..), _) => {}
-                        (_, Some(disr_expr)) => gate_feature_post!(
-                            &self,
-                            arbitrary_enum_discriminant,
-                            disr_expr.value.span,
-                            "discriminants on non-unit variants are experimental"
-                        ),
-                        _ => {}
-                    }
-                }
-
-                let has_feature = self.features.arbitrary_enum_discriminant;
-                if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
-                    self.maybe_report_invalid_custom_discriminants(&variants);
-                }
-            }
-
             ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, ref of_trait, .. }) => {
                 if let ast::ImplPolarity::Negative(span) = polarity {
                     gate_feature_post!(
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index d3e9a16a9a8..edccfa1c8ff 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -10,14 +10,14 @@ use rustc_span::{Span, Symbol};
 use crate::UnsupportedLiteralReason;
 
 #[derive(Diagnostic)]
-#[diag(attr::expected_one_cfg_pattern, code = "E0536")]
+#[diag(attr_expected_one_cfg_pattern, code = "E0536")]
 pub(crate) struct ExpectedOneCfgPattern {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::invalid_predicate, code = "E0537")]
+#[diag(attr_invalid_predicate, code = "E0537")]
 pub(crate) struct InvalidPredicate {
     #[primary_span]
     pub span: Span,
@@ -26,7 +26,7 @@ pub(crate) struct InvalidPredicate {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::multiple_item, code = "E0538")]
+#[diag(attr_multiple_item, code = "E0538")]
 pub(crate) struct MultipleItem {
     #[primary_span]
     pub span: Span,
@@ -35,7 +35,7 @@ pub(crate) struct MultipleItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::incorrect_meta_item, code = "E0539")]
+#[diag(attr_incorrect_meta_item, code = "E0539")]
 pub(crate) struct IncorrectMetaItem {
     #[primary_span]
     pub span: Span,
@@ -54,39 +54,39 @@ impl<'a> IntoDiagnostic<'a> for UnknownMetaItem<'_> {
         let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
         let mut diag = handler.struct_span_err_with_code(
             self.span,
-            fluent::attr::unknown_meta_item,
+            fluent::attr_unknown_meta_item,
             error_code!(E0541),
         );
         diag.set_arg("item", self.item);
         diag.set_arg("expected", expected.join(", "));
-        diag.span_label(self.span, fluent::attr::label);
+        diag.span_label(self.span, fluent::label);
         diag
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::missing_since, code = "E0542")]
+#[diag(attr_missing_since, code = "E0542")]
 pub(crate) struct MissingSince {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::missing_note, code = "E0543")]
+#[diag(attr_missing_note, code = "E0543")]
 pub(crate) struct MissingNote {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::multiple_stability_levels, code = "E0544")]
+#[diag(attr_multiple_stability_levels, code = "E0544")]
 pub(crate) struct MultipleStabilityLevels {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::invalid_issue_string, code = "E0545")]
+#[diag(attr_invalid_issue_string, code = "E0545")]
 pub(crate) struct InvalidIssueString {
     #[primary_span]
     pub span: Span,
@@ -99,31 +99,31 @@ pub(crate) struct InvalidIssueString {
 // translatable.
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidIssueStringCause {
-    #[label(attr::must_not_be_zero)]
+    #[label(must_not_be_zero)]
     MustNotBeZero {
         #[primary_span]
         span: Span,
     },
 
-    #[label(attr::empty)]
+    #[label(empty)]
     Empty {
         #[primary_span]
         span: Span,
     },
 
-    #[label(attr::invalid_digit)]
+    #[label(invalid_digit)]
     InvalidDigit {
         #[primary_span]
         span: Span,
     },
 
-    #[label(attr::pos_overflow)]
+    #[label(pos_overflow)]
     PosOverflow {
         #[primary_span]
         span: Span,
     },
 
-    #[label(attr::neg_overflow)]
+    #[label(neg_overflow)]
     NegOverflow {
         #[primary_span]
         span: Span,
@@ -144,21 +144,21 @@ impl InvalidIssueStringCause {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::missing_feature, code = "E0546")]
+#[diag(attr_missing_feature, code = "E0546")]
 pub(crate) struct MissingFeature {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::non_ident_feature, code = "E0546")]
+#[diag(attr_non_ident_feature, code = "E0546")]
 pub(crate) struct NonIdentFeature {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::missing_issue, code = "E0547")]
+#[diag(attr_missing_issue, code = "E0547")]
 pub(crate) struct MissingIssue {
     #[primary_span]
     pub span: Span,
@@ -167,7 +167,7 @@ pub(crate) struct MissingIssue {
 // FIXME: This diagnostic is identical to `IncorrectMetaItem`, barring the error code. Consider
 // changing this to `IncorrectMetaItem`. See #51489.
 #[derive(Diagnostic)]
-#[diag(attr::incorrect_meta_item, code = "E0551")]
+#[diag(attr_incorrect_meta_item, code = "E0551")]
 pub(crate) struct IncorrectMetaItem2 {
     #[primary_span]
     pub span: Span,
@@ -176,14 +176,14 @@ pub(crate) struct IncorrectMetaItem2 {
 // FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`?
 // It is more similar to `IncorrectReprFormatGeneric`.
 #[derive(Diagnostic)]
-#[diag(attr::incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")]
+#[diag(attr_incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")]
 pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::invalid_repr_hint_no_paren, code = "E0552")]
+#[diag(attr_invalid_repr_hint_no_paren, code = "E0552")]
 pub(crate) struct InvalidReprHintNoParen {
     #[primary_span]
     pub span: Span,
@@ -192,7 +192,7 @@ pub(crate) struct InvalidReprHintNoParen {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::invalid_repr_hint_no_value, code = "E0552")]
+#[diag(attr_invalid_repr_hint_no_value, code = "E0552")]
 pub(crate) struct InvalidReprHintNoValue {
     #[primary_span]
     pub span: Span,
@@ -213,13 +213,13 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
         let mut diag = handler.struct_span_err_with_code(
             self.span,
             match self.reason {
-                UnsupportedLiteralReason::Generic => fluent::attr::unsupported_literal_generic,
-                UnsupportedLiteralReason::CfgString => fluent::attr::unsupported_literal_cfg_string,
+                UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
+                UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
                 UnsupportedLiteralReason::DeprecatedString => {
-                    fluent::attr::unsupported_literal_deprecated_string
+                    fluent::attr_unsupported_literal_deprecated_string
                 }
                 UnsupportedLiteralReason::DeprecatedKvPair => {
-                    fluent::attr::unsupported_literal_deprecated_kv_pair
+                    fluent::attr_unsupported_literal_deprecated_kv_pair
                 }
             },
             error_code!(E0565),
@@ -227,7 +227,7 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
         if self.is_bytestr {
             diag.span_suggestion(
                 self.start_point_span,
-                fluent::attr::unsupported_literal_suggestion,
+                fluent::attr_unsupported_literal_suggestion,
                 "",
                 Applicability::MaybeIncorrect,
             );
@@ -237,7 +237,7 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::invalid_repr_align_need_arg, code = "E0589")]
+#[diag(attr_invalid_repr_align_need_arg, code = "E0589")]
 pub(crate) struct InvalidReprAlignNeedArg {
     #[primary_span]
     #[suggestion(code = "align(...)", applicability = "has-placeholders")]
@@ -245,7 +245,7 @@ pub(crate) struct InvalidReprAlignNeedArg {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::invalid_repr_generic, code = "E0589")]
+#[diag(attr_invalid_repr_generic, code = "E0589")]
 pub(crate) struct InvalidReprGeneric<'a> {
     #[primary_span]
     pub span: Span,
@@ -255,14 +255,14 @@ pub(crate) struct InvalidReprGeneric<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::incorrect_repr_format_align_one_arg, code = "E0693")]
+#[diag(attr_incorrect_repr_format_align_one_arg, code = "E0693")]
 pub(crate) struct IncorrectReprFormatAlignOneArg {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::incorrect_repr_format_generic, code = "E0693")]
+#[diag(attr_incorrect_repr_format_generic, code = "E0693")]
 pub(crate) struct IncorrectReprFormatGeneric<'a> {
     #[primary_span]
     pub span: Span,
@@ -275,7 +275,7 @@ pub(crate) struct IncorrectReprFormatGeneric<'a> {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum IncorrectReprFormatGenericCause<'a> {
-    #[suggestion(attr::suggestion, code = "{name}({int})", applicability = "machine-applicable")]
+    #[suggestion(suggestion, code = "{name}({int})", applicability = "machine-applicable")]
     Int {
         #[primary_span]
         span: Span,
@@ -287,11 +287,7 @@ pub(crate) enum IncorrectReprFormatGenericCause<'a> {
         int: u128,
     },
 
-    #[suggestion(
-        attr::suggestion,
-        code = "{name}({symbol})",
-        applicability = "machine-applicable"
-    )]
+    #[suggestion(suggestion, code = "{name}({symbol})", applicability = "machine-applicable")]
     Symbol {
         #[primary_span]
         span: Span,
@@ -317,28 +313,28 @@ impl<'a> IncorrectReprFormatGenericCause<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::rustc_promotable_pairing, code = "E0717")]
+#[diag(attr_rustc_promotable_pairing, code = "E0717")]
 pub(crate) struct RustcPromotablePairing {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::rustc_allowed_unstable_pairing, code = "E0789")]
+#[diag(attr_rustc_allowed_unstable_pairing, code = "E0789")]
 pub(crate) struct RustcAllowedUnstablePairing {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::cfg_predicate_identifier)]
+#[diag(attr_cfg_predicate_identifier)]
 pub(crate) struct CfgPredicateIdentifier {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::deprecated_item_suggestion)]
+#[diag(attr_deprecated_item_suggestion)]
 pub(crate) struct DeprecatedItemSuggestion {
     #[primary_span]
     pub span: Span,
@@ -351,21 +347,21 @@ pub(crate) struct DeprecatedItemSuggestion {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::expected_single_version_literal)]
+#[diag(attr_expected_single_version_literal)]
 pub(crate) struct ExpectedSingleVersionLiteral {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::expected_version_literal)]
+#[diag(attr_expected_version_literal)]
 pub(crate) struct ExpectedVersionLiteral {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::expects_feature_list)]
+#[diag(attr_expects_feature_list)]
 pub(crate) struct ExpectsFeatureList {
     #[primary_span]
     pub span: Span,
@@ -374,7 +370,7 @@ pub(crate) struct ExpectsFeatureList {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::expects_features)]
+#[diag(attr_expects_features)]
 pub(crate) struct ExpectsFeatures {
     #[primary_span]
     pub span: Span,
@@ -383,14 +379,14 @@ pub(crate) struct ExpectsFeatures {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::soft_no_args)]
+#[diag(attr_soft_no_args)]
 pub(crate) struct SoftNoArgs {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::unknown_version_literal)]
+#[diag(attr_unknown_version_literal)]
 pub(crate) struct UnknownVersionLiteral {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 02071ed6b36..dac6abe37f5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -5,14 +5,14 @@ use rustc_infer::infer::region_constraints::Constraint;
 use rustc_infer::infer::region_constraints::RegionConstraintData;
 use rustc_infer::infer::RegionVariableOrigin;
 use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
-use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
+use rustc_infer::traits::ObligationCause;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::RegionVid;
 use rustc_middle::ty::UniverseIndex;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op;
-use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
+use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
 
 use std::fmt;
@@ -240,9 +240,9 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
         let (ref infcx, key, _) =
             mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
-        let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-        type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
-        try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
+        let ocx = ObligationCtxt::new(infcx);
+        type_op_prove_predicate_with_cause(&ocx, key, cause);
+        try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
     }
 }
 
@@ -281,9 +281,7 @@ where
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
         let (ref infcx, key, _) =
             mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
-        let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
-        let mut selcx = SelectionContext::new(infcx);
+        let ocx = ObligationCtxt::new(infcx);
 
         // FIXME(lqd): Unify and de-duplicate the following with the actual
         // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
@@ -292,11 +290,9 @@ where
         // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
         // after #85499 lands to see if its fixes have erased this difference.
         let (param_env, value) = key.into_parts();
-        let Normalized { value: _, obligations } =
-            rustc_trait_selection::traits::normalize(&mut selcx, param_env, cause, value.value);
-        fulfill_cx.register_predicate_obligations(infcx, obligations);
+        let _ = ocx.normalize(cause, param_env, value.value);
 
-        try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
+        try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
     }
 }
 
@@ -329,9 +325,9 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
         let (ref infcx, key, _) =
             mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
-        let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-        type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)).ok()?;
-        try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
+        let ocx = ObligationCtxt::new(infcx);
+        type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?;
+        try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
     }
 }
 
@@ -372,25 +368,24 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
     }
 }
 
-#[instrument(skip(fulfill_cx, infcx), level = "debug")]
+#[instrument(skip(ocx), level = "debug")]
 fn try_extract_error_from_fulfill_cx<'tcx>(
-    mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
-    infcx: &InferCtxt<'tcx>,
+    ocx: &ObligationCtxt<'_, 'tcx>,
     placeholder_region: ty::Region<'tcx>,
     error_region: Option<ty::Region<'tcx>>,
 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
     // We generally shouldn't have errors here because the query was
     // already run, but there's no point using `delay_span_bug`
     // when we're going to emit an error here anyway.
-    let _errors = fulfill_cx.select_all_or_error(infcx);
-    let region_constraints = infcx.with_region_constraints(|r| r.clone());
+    let _errors = ocx.select_all_or_error();
+    let region_constraints = ocx.infcx.with_region_constraints(|r| r.clone());
     try_extract_error_from_region_constraints(
-        infcx,
+        ocx.infcx,
         placeholder_region,
         error_region,
         &region_constraints,
-        |vid| infcx.region_var_origin(vid),
-        |vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))),
+        |vid| ocx.infcx.region_var_origin(vid),
+        |vid| ocx.infcx.universe_of_region(ocx.infcx.tcx.mk_region(ty::ReVar(vid))),
     )
 }
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 2a8bd4d30ab..583bc2e281d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -492,10 +492,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
                 return false;
             };
+            // Regions are already solved, so we must use a fresh InferCtxt,
+            // but the type has region variables, so erase those.
             tcx.infer_ctxt()
                 .build()
-                .type_implements_trait(default_trait, ty, ty::List::empty(), param_env)
-                .may_apply()
+                .type_implements_trait(
+                    default_trait,
+                    tcx.erase_regions(ty),
+                    ty::List::empty(),
+                    param_env,
+                )
+                .must_apply_modulo_regions()
         };
 
         let assign_value = match ty.kind() {
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 1c01e78abd4..582d683dd35 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -1,8 +1,5 @@
 //! Print diagnostics to explain why values are borrowed.
 
-use std::collections::VecDeque;
-
-use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::NllRegionVariableOrigin;
@@ -359,19 +356,37 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let borrow_region_vid = borrow.region;
         debug!(?borrow_region_vid);
 
-        let region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
+        let mut region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
         debug!(?region_sub);
 
-        match find_use::find(body, regioncx, tcx, region_sub, location) {
+        let mut use_location = location;
+        let mut use_in_later_iteration_of_loop = false;
+
+        if region_sub == borrow_region_vid {
+            // When `region_sub` is the same as `borrow_region_vid` (the location where the borrow is
+            // issued is the same location that invalidates the reference), this is likely a loop iteration
+            // - in this case, try using the loop terminator location in `find_sub_region_live_at`.
+            if let Some(loop_terminator_location) =
+                regioncx.find_loop_terminator_location(borrow.region, body)
+            {
+                region_sub = self
+                    .regioncx
+                    .find_sub_region_live_at(borrow_region_vid, loop_terminator_location);
+                debug!("explain_why_borrow_contains_point: region_sub in loop={:?}", region_sub);
+                use_location = loop_terminator_location;
+                use_in_later_iteration_of_loop = true;
+            }
+        }
+
+        match find_use::find(body, regioncx, tcx, region_sub, use_location) {
             Some(Cause::LiveVar(local, location)) => {
                 let span = body.source_info(location).span;
                 let spans = self
                     .move_spans(Place::from(local).as_ref(), location)
                     .or_else(|| self.borrow_spans(span, location));
 
-                let borrow_location = location;
-                if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
-                    let later_use = self.later_use_kind(borrow, spans, location);
+                if use_in_later_iteration_of_loop {
+                    let later_use = self.later_use_kind(borrow, spans, use_location);
                     BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2)
                 } else {
                     // Check if the location represents a `FakeRead`, and adapt the error
@@ -425,131 +440,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
     }
 
-    /// true if `borrow_location` can reach `use_location` by going through a loop and
-    /// `use_location` is also inside of that loop
-    fn is_use_in_later_iteration_of_loop(
-        &self,
-        borrow_location: Location,
-        use_location: Location,
-    ) -> bool {
-        let back_edge = self.reach_through_backedge(borrow_location, use_location);
-        back_edge.map_or(false, |back_edge| self.can_reach_head_of_loop(use_location, back_edge))
-    }
-
-    /// Returns the outmost back edge if `from` location can reach `to` location passing through
-    /// that back edge
-    fn reach_through_backedge(&self, from: Location, to: Location) -> Option<Location> {
-        let mut visited_locations = FxHashSet::default();
-        let mut pending_locations = VecDeque::new();
-        visited_locations.insert(from);
-        pending_locations.push_back(from);
-        debug!("reach_through_backedge: from={:?} to={:?}", from, to,);
-
-        let mut outmost_back_edge = None;
-        while let Some(location) = pending_locations.pop_front() {
-            debug!(
-                "reach_through_backedge: location={:?} outmost_back_edge={:?}
-                   pending_locations={:?} visited_locations={:?}",
-                location, outmost_back_edge, pending_locations, visited_locations
-            );
-
-            if location == to && outmost_back_edge.is_some() {
-                // We've managed to reach the use location
-                debug!("reach_through_backedge: found!");
-                return outmost_back_edge;
-            }
-
-            let block = &self.body.basic_blocks[location.block];
-
-            if location.statement_index < block.statements.len() {
-                let successor = location.successor_within_block();
-                if visited_locations.insert(successor) {
-                    pending_locations.push_back(successor);
-                }
-            } else {
-                pending_locations.extend(
-                    block
-                        .terminator()
-                        .successors()
-                        .map(|bb| Location { statement_index: 0, block: bb })
-                        .filter(|s| visited_locations.insert(*s))
-                        .map(|s| {
-                            if self.is_back_edge(location, s) {
-                                match outmost_back_edge {
-                                    None => {
-                                        outmost_back_edge = Some(location);
-                                    }
-
-                                    Some(back_edge)
-                                        if location.dominates(back_edge, &self.dominators) =>
-                                    {
-                                        outmost_back_edge = Some(location);
-                                    }
-
-                                    Some(_) => {}
-                                }
-                            }
-
-                            s
-                        }),
-                );
-            }
-        }
-
-        None
-    }
-
-    /// true if `from` location can reach `loop_head` location and `loop_head` dominates all the
-    /// intermediate nodes
-    fn can_reach_head_of_loop(&self, from: Location, loop_head: Location) -> bool {
-        self.find_loop_head_dfs(from, loop_head, &mut FxHashSet::default())
-    }
-
-    fn find_loop_head_dfs(
-        &self,
-        from: Location,
-        loop_head: Location,
-        visited_locations: &mut FxHashSet<Location>,
-    ) -> bool {
-        visited_locations.insert(from);
-
-        if from == loop_head {
-            return true;
-        }
-
-        if loop_head.dominates(from, &self.dominators) {
-            let block = &self.body.basic_blocks[from.block];
-
-            if from.statement_index < block.statements.len() {
-                let successor = from.successor_within_block();
-
-                if !visited_locations.contains(&successor)
-                    && self.find_loop_head_dfs(successor, loop_head, visited_locations)
-                {
-                    return true;
-                }
-            } else {
-                for bb in block.terminator().successors() {
-                    let successor = Location { statement_index: 0, block: bb };
-
-                    if !visited_locations.contains(&successor)
-                        && self.find_loop_head_dfs(successor, loop_head, visited_locations)
-                    {
-                        return true;
-                    }
-                }
-            }
-        }
-
-        false
-    }
-
-    /// True if an edge `source -> target` is a backedge -- in other words, if the target
-    /// dominates the source.
-    fn is_back_edge(&self, source: Location, target: Location) -> bool {
-        target.dominates(source, &self.dominators)
-    }
-
     /// Determine how the borrow was later used.
     /// First span returned points to the location of the conflicting use
     /// Second span if `Some` is returned in the case of closures and points
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 4d251cf7ac7..c044dbaba47 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -251,7 +251,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr))
             .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr))
             .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr))
-            .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr));
+            .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr))
+            .or_else(|| self.give_name_if_anonymous_region_appears_in_arg_position_impl_trait(fr));
 
         if let Some(ref value) = value {
             self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone());
@@ -869,13 +870,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             return None;
         }
 
-        let mut found = false;
-        tcx.fold_regions(tcx.type_of(region_parent), |r: ty::Region<'tcx>, _| {
-            if *r == ty::ReEarlyBound(region) {
-                found = true;
-            }
-            r
-        });
+        let found = tcx
+            .any_free_region_meets(&tcx.type_of(region_parent), |r| *r == ty::ReEarlyBound(region));
 
         Some(RegionName {
             name: self.synthesize_region_name(),
@@ -888,4 +884,92 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             ),
         })
     }
+
+    fn give_name_if_anonymous_region_appears_in_arg_position_impl_trait(
+        &self,
+        fr: RegionVid,
+    ) -> Option<RegionName> {
+        let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else {
+            return None;
+        };
+        if region.has_name() {
+            return None;
+        };
+
+        let predicates = self
+            .infcx
+            .tcx
+            .predicates_of(self.body.source.def_id())
+            .instantiate_identity(self.infcx.tcx)
+            .predicates;
+
+        if let Some(upvar_index) = self
+            .regioncx
+            .universal_regions()
+            .defining_ty
+            .upvar_tys()
+            .position(|ty| self.any_param_predicate_mentions(&predicates, ty, region))
+        {
+            let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
+                self.infcx.tcx,
+                &self.upvars,
+                upvar_index,
+            );
+            let region_name = self.synthesize_region_name();
+
+            Some(RegionName {
+                name: region_name,
+                source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name),
+            })
+        } else if let Some(arg_index) = self
+            .regioncx
+            .universal_regions()
+            .unnormalized_input_tys
+            .iter()
+            .position(|ty| self.any_param_predicate_mentions(&predicates, *ty, region))
+        {
+            let (arg_name, arg_span) = self.regioncx.get_argument_name_and_span_for_region(
+                self.body,
+                &self.local_names,
+                arg_index,
+            );
+            let region_name = self.synthesize_region_name();
+
+            Some(RegionName {
+                name: region_name,
+                source: RegionNameSource::AnonRegionFromArgument(
+                    RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?.to_string()),
+                ),
+            })
+        } else {
+            None
+        }
+    }
+
+    fn any_param_predicate_mentions(
+        &self,
+        predicates: &[ty::Predicate<'tcx>],
+        ty: Ty<'tcx>,
+        region: ty::EarlyBoundRegion,
+    ) -> bool {
+        let tcx = self.infcx.tcx;
+        ty.walk().any(|arg| {
+            if let ty::GenericArgKind::Type(ty) = arg.unpack()
+                && let ty::Param(_) = ty.kind()
+            {
+                predicates.iter().any(|pred| {
+                    match pred.kind().skip_binder() {
+                        ty::PredicateKind::Trait(data) if data.self_ty() == ty => {}
+                        ty::PredicateKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
+                        _ => return false,
+                    }
+                    tcx.any_free_region_meets(pred, |r| {
+                        *r == ty::ReEarlyBound(region)
+                    })
+                })
+            } else {
+                false
+            }
+        })
+    }
 }
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 4cefd1ec387..8b63294fbab 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -15,7 +15,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound,
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
 use rustc_middle::mir::{
     Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
-    ConstraintCategory, Local, Location, ReturnConstraint,
+    ConstraintCategory, Local, Location, ReturnConstraint, TerminatorKind,
 };
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::ObligationCauseCode;
@@ -2236,6 +2236,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
         self.universe_causes[&universe].clone()
     }
+
+    /// Tries to find the terminator of the loop in which the region 'r' resides.
+    /// Returns the location of the terminator if found.
+    pub(crate) fn find_loop_terminator_location(
+        &self,
+        r: RegionVid,
+        body: &Body<'_>,
+    ) -> Option<Location> {
+        let scc = self.constraint_sccs.scc(r.to_region_vid());
+        let locations = self.scc_values.locations_outlived_by(scc);
+        for location in locations {
+            let bb = &body[location.block];
+            if let Some(terminator) = &bb.terminator {
+                // terminator of a loop should be TerminatorKind::FalseUnwind
+                if let TerminatorKind::FalseUnwind { .. } = terminator.kind {
+                    return Some(location);
+                }
+            }
+        }
+        None
+    }
 }
 
 impl<'tcx> RegionDefinition<'tcx> {
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index a7c4671665f..465f353aaa3 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -2,12 +2,10 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::OpaqueTyOrigin;
-use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
 use rustc_infer::infer::TyCtxtInferExt as _;
 use rustc_infer::infer::{DefiningAnchor, InferCtxt};
 use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
-use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
+use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{
     self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable,
@@ -16,8 +14,6 @@ use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::TraitEngineExt as _;
 
-use crate::session_diagnostics::ConstNotUsedTraitAlias;
-
 use super::RegionInferenceContext;
 
 impl<'tcx> RegionInferenceContext<'tcx> {
@@ -229,31 +225,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
             return self.tcx.ty_error();
         }
 
-        let OpaqueTypeKey { def_id, substs } = opaque_type_key;
-
-        // Use substs to build up a reverse map from regions to their
-        // identity mappings. This is necessary because of `impl
-        // Trait` lifetimes are computed by replacing existing
-        // 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(self.tcx, def_id.to_def_id());
-        debug!(?id_substs);
-        let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
-            substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
-        debug!("map = {:#?}", map);
-
-        // Convert the type from the function into a type valid outside
-        // the function, by replacing invalid regions with 'static,
-        // after producing an error for each of them.
-        let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
-            self.tcx,
-            opaque_type_key,
-            map,
-            instantiated_ty.ty,
-            instantiated_ty.span,
-        ));
-        debug!(?definition_ty);
+        let definition_ty = instantiated_ty
+            .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false, origin)
+            .ty;
 
         if !check_opaque_type_parameter_valid(
             self.tcx,
@@ -269,6 +243,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         let OpaqueTyOrigin::TyAlias = origin else {
             return definition_ty;
         };
+        let def_id = opaque_type_key.def_id;
         // This logic duplicates most of `check_opaque_meets_bounds`.
         // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
         let param_env = self.tcx.param_env(def_id);
@@ -284,15 +259,15 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
             .to_predicate(infcx.tcx);
         let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
 
+        let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id());
+
         // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
         // the bounds that the function supplies.
-        match infcx.register_hidden_type(
-            OpaqueTypeKey { def_id, substs: id_substs },
-            ObligationCause::misc(instantiated_ty.span, body_id),
-            param_env,
-            definition_ty,
-            origin,
-        ) {
+        let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs);
+        match infcx
+            .at(&ObligationCause::misc(instantiated_ty.span, body_id), param_env)
+            .eq(opaque_ty, definition_ty)
+        {
             Ok(infer_ok) => {
                 for obligation in infer_ok.obligations {
                     fulfillment_cx.register_predicate_obligation(&infcx, obligation);
@@ -303,7 +278,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
                     .err_ctxt()
                     .report_mismatched_types(
                         &ObligationCause::misc(instantiated_ty.span, body_id),
-                        self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
+                        opaque_ty,
                         definition_ty,
                         err,
                     )
@@ -424,221 +399,3 @@ fn check_opaque_type_parameter_valid(
     }
     true
 }
-
-struct ReverseMapper<'tcx> {
-    tcx: TyCtxt<'tcx>,
-
-    key: ty::OpaqueTypeKey<'tcx>,
-    map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
-    do_not_error: bool,
-
-    /// initially `Some`, set to `None` once error has been reported
-    hidden_ty: Option<Ty<'tcx>>,
-
-    /// Span of function being checked.
-    span: Span,
-}
-
-impl<'tcx> ReverseMapper<'tcx> {
-    fn new(
-        tcx: TyCtxt<'tcx>,
-        key: ty::OpaqueTypeKey<'tcx>,
-        map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
-        hidden_ty: Ty<'tcx>,
-        span: Span,
-    ) -> Self {
-        Self { tcx, key, map, do_not_error: false, hidden_ty: Some(hidden_ty), span }
-    }
-
-    fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
-        assert!(!self.do_not_error);
-        self.do_not_error = true;
-        let kind = kind.fold_with(self);
-        self.do_not_error = false;
-        kind
-    }
-
-    fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
-        assert!(!self.do_not_error);
-        kind.fold_with(self)
-    }
-}
-
-impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    #[instrument(skip(self), level = "debug")]
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match *r {
-            // Ignore bound regions and `'static` regions that appear in the
-            // type, we only need to remap regions that reference lifetimes
-            // from the function declaration.
-            // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
-            ty::ReLateBound(..) | ty::ReStatic => return r,
-
-            // If regions have been erased (by writeback), don't try to unerase
-            // them.
-            ty::ReErased => return r,
-
-            // The regions that we expect from borrow checking.
-            ty::ReEarlyBound(_) | ty::ReFree(_) => {}
-
-            ty::RePlaceholder(_) | ty::ReVar(_) => {
-                // All of the regions in the type should either have been
-                // erased by writeback, or mapped back to named regions by
-                // borrow checking.
-                bug!("unexpected region kind in opaque type: {:?}", r);
-            }
-        }
-
-        let generics = self.tcx().generics_of(self.key.def_id);
-        match self.map.get(&r.into()).map(|k| k.unpack()) {
-            Some(GenericArgKind::Lifetime(r1)) => r1,
-            Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
-            None if self.do_not_error => self.tcx.lifetimes.re_static,
-            None if generics.parent.is_some() => {
-                if let Some(hidden_ty) = self.hidden_ty.take() {
-                    unexpected_hidden_region_diagnostic(
-                        self.tcx,
-                        self.tcx.def_span(self.key.def_id),
-                        hidden_ty,
-                        r,
-                        self.key,
-                    )
-                    .emit();
-                }
-                self.tcx.lifetimes.re_static
-            }
-            None => {
-                self.tcx
-                    .sess
-                    .struct_span_err(self.span, "non-defining opaque type use in defining scope")
-                    .span_label(
-                        self.span,
-                        format!(
-                            "lifetime `{}` is part of concrete type but not used in \
-                                 parameter list of the `impl Trait` type alias",
-                            r
-                        ),
-                    )
-                    .emit();
-
-                self.tcx().lifetimes.re_static
-            }
-        }
-    }
-
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        match *ty.kind() {
-            ty::Closure(def_id, substs) => {
-                // I am a horrible monster and I pray for death. When
-                // we encounter a closure here, it is always a closure
-                // from within the function that we are currently
-                // type-checking -- one that is now being encapsulated
-                // in an opaque type. Ideally, we would
-                // go through the types/lifetimes that it references
-                // and treat them just like we would any other type,
-                // which means we would error out if we find any
-                // reference to a type/region that is not in the
-                // "reverse map".
-                //
-                // **However,** in the case of closures, there is a
-                // somewhat subtle (read: hacky) consideration. The
-                // problem is that our closure types currently include
-                // all the lifetime parameters declared on the
-                // enclosing function, even if they are unused by the
-                // closure itself. We can't readily filter them out,
-                // so here we replace those values with `'empty`. This
-                // can't really make a difference to the rest of the
-                // compiler; those regions are ignored for the
-                // outlives relation, and hence don't affect trait
-                // selection or auto traits, and they are erased
-                // during codegen.
-
-                let generics = self.tcx.generics_of(def_id);
-                let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
-                    if index < generics.parent_count {
-                        // Accommodate missing regions in the parent kinds...
-                        self.fold_kind_no_missing_regions_error(kind)
-                    } else {
-                        // ...but not elsewhere.
-                        self.fold_kind_normally(kind)
-                    }
-                }));
-
-                self.tcx.mk_closure(def_id, substs)
-            }
-
-            ty::Generator(def_id, substs, movability) => {
-                let generics = self.tcx.generics_of(def_id);
-                let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
-                    if index < generics.parent_count {
-                        // Accommodate missing regions in the parent kinds...
-                        self.fold_kind_no_missing_regions_error(kind)
-                    } else {
-                        // ...but not elsewhere.
-                        self.fold_kind_normally(kind)
-                    }
-                }));
-
-                self.tcx.mk_generator(def_id, substs, movability)
-            }
-
-            ty::Param(param) => {
-                // Look it up in the substitution list.
-                match self.map.get(&ty.into()).map(|k| k.unpack()) {
-                    // Found it in the substitution list; replace with the parameter from the
-                    // opaque type.
-                    Some(GenericArgKind::Type(t1)) => t1,
-                    Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
-                    None => {
-                        debug!(?param, ?self.map);
-                        self.tcx
-                            .sess
-                            .struct_span_err(
-                                self.span,
-                                &format!(
-                                    "type parameter `{}` is part of concrete type but not \
-                                          used in parameter list for the `impl Trait` type alias",
-                                    ty
-                                ),
-                            )
-                            .emit();
-
-                        self.tcx().ty_error()
-                    }
-                }
-            }
-
-            _ => ty.super_fold_with(self),
-        }
-    }
-
-    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        trace!("checking const {:?}", ct);
-        // Find a const parameter
-        match ct.kind() {
-            ty::ConstKind::Param(..) => {
-                // Look it up in the substitution list.
-                match self.map.get(&ct.into()).map(|k| k.unpack()) {
-                    // Found it in the substitution list, replace with the parameter from the
-                    // opaque type.
-                    Some(GenericArgKind::Const(c1)) => c1,
-                    Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
-                    None => {
-                        self.tcx.sess.emit_err(ConstNotUsedTraitAlias {
-                            ct: ct.to_string(),
-                            span: self.span,
-                        });
-
-                        self.tcx().const_error(ct.ty())
-                    }
-                }
-            }
-
-            _ => ct,
-        }
-    }
-}
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index d737432f0ef..f3023769081 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -1,8 +1,8 @@
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
 use rustc_middle::mir::visit::{MutVisitor, TyContext};
+use rustc_middle::mir::Constant;
 use rustc_middle::mir::{Body, Location, Promoted};
-use rustc_middle::mir::{Constant, ConstantKind};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 
@@ -38,21 +38,6 @@ where
     })
 }
 
-// FIXME(valtrees): This function is necessary because `fold_regions`
-// panics for mir constants in the visitor.
-//
-// Once `visit_mir_constant` is removed we can also remove this function
-// and just use `renumber_regions`.
-fn renumber_regions_in_mir_constant<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    value: ConstantKind<'tcx>,
-) -> ConstantKind<'tcx> {
-    infcx.tcx.super_fold_regions(value, |_region, _depth| {
-        let origin = NllRegionVariableOrigin::Existential { from_forall: false };
-        infcx.next_nll_region_var(origin)
-    })
-}
-
 struct NllVisitor<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
 }
@@ -64,13 +49,6 @@ impl<'a, 'tcx> NllVisitor<'a, 'tcx> {
     {
         renumber_regions(self.infcx, value)
     }
-
-    fn renumber_regions_in_mir_constant(
-        &mut self,
-        value: ConstantKind<'tcx>,
-    ) -> ConstantKind<'tcx> {
-        renumber_regions_in_mir_constant(self.infcx, value)
-    }
 }
 
 impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
@@ -103,7 +81,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
     #[instrument(skip(self), level = "debug")]
     fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _location: Location) {
         let literal = constant.literal;
-        constant.literal = self.renumber_regions_in_mir_constant(literal);
+        constant.literal = self.renumber_regions(literal);
         debug!("constant: {:#?}", constant);
     }
 }
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index 9f19453a1a6..fe24f85fae1 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -6,7 +6,7 @@ use rustc_span::Span;
 use crate::diagnostics::RegionName;
 
 #[derive(Diagnostic)]
-#[diag(borrowck::move_unsized, code = "E0161")]
+#[diag(borrowck_move_unsized, code = "E0161")]
 pub(crate) struct MoveUnsized<'tcx> {
     pub ty: Ty<'tcx>,
     #[primary_span]
@@ -15,7 +15,7 @@ pub(crate) struct MoveUnsized<'tcx> {
 }
 
 #[derive(Diagnostic)]
-#[diag(borrowck::higher_ranked_lifetime_error)]
+#[diag(borrowck_higher_ranked_lifetime_error)]
 pub(crate) struct HigherRankedLifetimeError {
     #[subdiagnostic]
     pub cause: Option<HigherRankedErrorCause>,
@@ -25,21 +25,21 @@ pub(crate) struct HigherRankedLifetimeError {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum HigherRankedErrorCause {
-    #[note(borrowck::could_not_prove)]
+    #[note(borrowck_could_not_prove)]
     CouldNotProve { predicate: String },
-    #[note(borrowck::could_not_normalize)]
+    #[note(borrowck_could_not_normalize)]
     CouldNotNormalize { value: String },
 }
 
 #[derive(Diagnostic)]
-#[diag(borrowck::higher_ranked_subtype_error)]
+#[diag(borrowck_higher_ranked_subtype_error)]
 pub(crate) struct HigherRankedSubtypeError {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(borrowck::generic_does_not_live_long_enough)]
+#[diag(borrowck_generic_does_not_live_long_enough)]
 pub(crate) struct GenericDoesNotLiveLongEnough {
     pub kind: String,
     #[primary_span]
@@ -47,24 +47,15 @@ pub(crate) struct GenericDoesNotLiveLongEnough {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(borrowck::var_does_not_need_mut)]
+#[diag(borrowck_var_does_not_need_mut)]
 pub(crate) struct VarNeedNotMut {
-    #[suggestion_short(applicability = "machine-applicable", code = "")]
+    #[suggestion(style = "short", applicability = "machine-applicable", code = "")]
     pub span: Span,
 }
-
-#[derive(Diagnostic)]
-#[diag(borrowck::const_not_used_in_type_alias)]
-pub(crate) struct ConstNotUsedTraitAlias {
-    pub ct: String,
-    #[primary_span]
-    pub span: Span,
-}
-
 #[derive(Diagnostic)]
-#[diag(borrowck::var_cannot_escape_closure)]
+#[diag(borrowck_var_cannot_escape_closure)]
 #[note]
-#[note(borrowck::cannot_escape)]
+#[note(cannot_escape)]
 pub(crate) struct FnMutError {
     #[primary_span]
     pub span: Span,
@@ -74,17 +65,17 @@ pub(crate) struct FnMutError {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum VarHereDenote {
-    #[label(borrowck::var_here_captured)]
+    #[label(borrowck_var_here_captured)]
     Captured {
         #[primary_span]
         span: Span,
     },
-    #[label(borrowck::var_here_defined)]
+    #[label(borrowck_var_here_defined)]
     Defined {
         #[primary_span]
         span: Span,
     },
-    #[label(borrowck::closure_inferred_mut)]
+    #[label(borrowck_closure_inferred_mut)]
     FnMutInferred {
         #[primary_span]
         span: Span,
@@ -93,17 +84,17 @@ pub(crate) enum VarHereDenote {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum FnMutReturnTypeErr {
-    #[label(borrowck::returned_closure_escaped)]
+    #[label(borrowck_returned_closure_escaped)]
     ReturnClosure {
         #[primary_span]
         span: Span,
     },
-    #[label(borrowck::returned_async_block_escaped)]
+    #[label(borrowck_returned_async_block_escaped)]
     ReturnAsyncBlock {
         #[primary_span]
         span: Span,
     },
-    #[label(borrowck::returned_ref_escaped)]
+    #[label(borrowck_returned_ref_escaped)]
     ReturnRef {
         #[primary_span]
         span: Span,
@@ -111,7 +102,7 @@ pub(crate) enum FnMutReturnTypeErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(borrowck::lifetime_constraints_error)]
+#[diag(borrowck_lifetime_constraints_error)]
 pub(crate) struct LifetimeOutliveErr {
     #[primary_span]
     pub span: Span,
@@ -119,7 +110,7 @@ pub(crate) struct LifetimeOutliveErr {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum LifetimeReturnCategoryErr<'a> {
-    #[label(borrowck::returned_lifetime_wrong)]
+    #[label(borrowck_returned_lifetime_wrong)]
     WrongReturn {
         #[primary_span]
         span: Span,
@@ -127,7 +118,7 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> {
         outlived_fr_name: RegionName,
         fr_name: &'a RegionName,
     },
-    #[label(borrowck::returned_lifetime_short)]
+    #[label(borrowck_returned_lifetime_short)]
     ShortReturn {
         #[primary_span]
         span: Span,
@@ -151,7 +142,7 @@ impl IntoDiagnosticArg for RegionName {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum RequireStaticErr {
-    #[note(borrowck::used_impl_require_static)]
+    #[note(borrowck_used_impl_require_static)]
     UsedImpl {
         #[primary_span]
         multi_span: MultiSpan,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index dc0f0e7cd3c..3c1c3ab45ce 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1630,7 +1630,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
             let op_arg_ty = self.normalize(op_arg_ty, term_location);
             let category = if from_hir_call {
-                ConstraintCategory::CallArgument(func_ty)
+                ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty))
             } else {
                 ConstraintCategory::Boring
             };
@@ -1783,7 +1783,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         // `Sized` bound in no way depends on precise regions, so this
         // shouldn't affect `is_sized`.
         let erased_ty = tcx.erase_regions(ty);
-        if !erased_ty.is_sized(tcx.at(span), self.param_env) {
+        if !erased_ty.is_sized(tcx, self.param_env) {
             // in current MIR construction, all non-control-flow rvalue
             // expressions evaluate through `as_temp` or `into` a return
             // slot or local, so to find all unsized rvalues it is enough
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index c97a6a1a658..4f2dc263bf5 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,6 +1,6 @@
 use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
 use rustc_infer::infer::NllRegionVariableOrigin;
-use rustc_infer::traits::ObligationCause;
+use rustc_infer::traits::PredicateObligations;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::TypeRelation;
@@ -155,27 +155,16 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
         true
     }
 
-    fn register_opaque_type(
+    fn register_opaque_type_obligations(
         &mut self,
-        a: Ty<'tcx>,
-        b: Ty<'tcx>,
-        a_is_expected: bool,
+        obligations: PredicateObligations<'tcx>,
     ) -> Result<(), TypeError<'tcx>> {
-        let param_env = self.param_env();
-        let span = self.span();
-        let def_id = self.type_checker.body.source.def_id().expect_local();
-        let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id);
-        let cause = ObligationCause::misc(span, body_id);
         self.type_checker
             .fully_perform_op(
                 self.locations,
                 self.category,
                 InstantiateOpaqueType {
-                    obligations: self
-                        .type_checker
-                        .infcx
-                        .handle_opaque_type(a, b, a_is_expected, &cause, param_env)?
-                        .obligations,
+                    obligations,
                     // These fields are filled in during execution of the operation
                     base_universe: None,
                     region_constraints: None,
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 51d262a881b..2beb5e0ab5d 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -414,7 +414,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
 
         let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
 
-        // If this is is a 'root' body (not a closure/generator/inline const), then
+        // If this is a 'root' body (not a closure/generator/inline const), then
         // there are no extern regions, so the local regions start at the same
         // position as the (empty) sub-list of extern regions
         let first_local_index = if self.mir_def.did.to_def_id() == typeck_root_def_id {
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index 6469d0d7b88..467fa932a15 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -23,5 +23,5 @@ rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
 tracing = "0.1"
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
new file mode 100644
index 00000000000..eaf1b1167cf
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -0,0 +1,104 @@
+use crate::util::check_builtin_macro_attribute;
+
+use rustc_ast::ptr::P;
+use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind};
+use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe};
+use rustc_expand::base::{Annotatable, ExtCtxt};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::Span;
+use thin_vec::thin_vec;
+
+pub fn expand(
+    ecx: &mut ExtCtxt<'_>,
+    _span: Span,
+    meta_item: &ast::MetaItem,
+    item: Annotatable,
+) -> Vec<Annotatable> {
+    check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler);
+
+    let orig_item = item.clone();
+    let not_function = || {
+        ecx.sess
+            .parse_sess
+            .span_diagnostic
+            .span_err(item.span(), "alloc_error_handler must be a function");
+        vec![orig_item.clone()]
+    };
+
+    // Allow using `#[alloc_error_handler]` on an item statement
+    // FIXME - if we get deref patterns, use them to reduce duplication here
+    let (item, is_stmt, sig_span) = match &item {
+        Annotatable::Item(item) => match item.kind {
+            ItemKind::Fn(ref fn_kind) => (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)),
+            _ => return not_function(),
+        },
+        Annotatable::Stmt(stmt) => match &stmt.kind {
+            StmtKind::Item(item_) => match item_.kind {
+                ItemKind::Fn(ref fn_kind) => {
+                    (item_, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
+                }
+                _ => return not_function(),
+            },
+            _ => return not_function(),
+        },
+        _ => return not_function(),
+    };
+
+    // Generate a bunch of new items using the AllocFnFactory
+    let span = ecx.with_def_site_ctxt(item.span);
+
+    // Generate item statements for the allocator methods.
+    let stmts = vec![generate_handler(ecx, item.ident, span, sig_span)];
+
+    // Generate anonymous constant serving as container for the allocator methods.
+    let const_ty = ecx.ty(sig_span, TyKind::Tup(Vec::new()));
+    let const_body = ecx.expr_block(ecx.block(span, stmts));
+    let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
+    let const_item = if is_stmt {
+        Annotatable::Stmt(P(ecx.stmt_item(span, const_item)))
+    } else {
+        Annotatable::Item(const_item)
+    };
+
+    // Return the original item and the new methods.
+    vec![orig_item, const_item]
+}
+
+// #[rustc_std_internal_symbol]
+// unsafe fn __rg_oom(size: usize, align: usize) -> ! {
+//     handler(core::alloc::Layout::from_size_align_unchecked(size, align))
+// }
+fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt {
+    let usize = cx.path_ident(span, Ident::new(sym::usize, span));
+    let ty_usize = cx.ty_path(usize);
+    let size = Ident::from_str_and_span("size", span);
+    let align = Ident::from_str_and_span("align", span);
+
+    let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]);
+    let layout_new = cx.expr_path(cx.path(span, layout_new));
+    let layout =
+        cx.expr_call(span, layout_new, vec![cx.expr_ident(span, size), cx.expr_ident(span, align)]);
+
+    let call = cx.expr_call_ident(sig_span, handler, vec![layout]);
+
+    let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never));
+    let params = vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)];
+    let decl = cx.fn_decl(params, never);
+    let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() };
+    let sig = FnSig { decl, header, span: span };
+
+    let body = Some(cx.block_expr(call));
+    let kind = ItemKind::Fn(Box::new(Fn {
+        defaultness: ast::Defaultness::Final,
+        sig,
+        generics: Generics::default(),
+        body,
+    }));
+
+    let special = sym::rustc_std_internal_symbol;
+    let special = cx.meta_word(span, special);
+    let attrs = thin_vec![cx.attribute(special)];
+
+    let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind);
+    cx.stmt_item(sig_span, item)
+}
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index 46b54eae384..5638c2f6180 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -36,7 +36,7 @@ pub fn expand_cfg(
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros::requires_cfg_pattern)]
+#[diag(builtin_macros_requires_cfg_pattern)]
 struct RequiresCfgPattern {
     #[primary_span]
     #[label]
@@ -44,7 +44,7 @@ struct RequiresCfgPattern {
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros::expected_one_cfg_pattern)]
+#[diag(builtin_macros_expected_one_cfg_pattern)]
 struct OneCfgPattern {
     #[primary_span]
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index 009f3c783d4..750f1fe121f 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -210,8 +210,15 @@ impl CfgEval<'_, '_> {
 }
 
 impl MutVisitor for CfgEval<'_, '_> {
+    #[instrument(level = "trace", skip(self))]
     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
-        self.cfg.configure_expr(expr);
+        self.cfg.configure_expr(expr, false);
+        mut_visit::noop_visit_expr(expr, self);
+    }
+
+    #[instrument(level = "trace", skip(self))]
+    fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
+        self.cfg.configure_expr(expr, true);
         mut_visit::noop_visit_expr(expr, self);
     }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index a65d0bad6de..ee346047a0b 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -131,6 +131,8 @@ fn inject_impl_of_structural_trait(
     // Create generics param list for where clauses and impl headers
     let mut generics = generics.clone();
 
+    let ctxt = span.ctxt();
+
     // Create the type of `self`.
     //
     // in addition, remove defaults from generic params (impls cannot have them).
@@ -138,16 +140,18 @@ fn inject_impl_of_structural_trait(
         .params
         .iter_mut()
         .map(|param| match &mut param.kind {
-            ast::GenericParamKind::Lifetime => {
-                ast::GenericArg::Lifetime(cx.lifetime(span, param.ident))
-            }
+            ast::GenericParamKind::Lifetime => ast::GenericArg::Lifetime(
+                cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident),
+            ),
             ast::GenericParamKind::Type { default } => {
                 *default = None;
-                ast::GenericArg::Type(cx.ty_ident(span, param.ident))
+                ast::GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
             }
             ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
                 *default = None;
-                ast::GenericArg::Const(cx.const_ident(span, param.ident))
+                ast::GenericArg::Const(
+                    cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident),
+                )
             }
         })
         .collect();
@@ -174,6 +178,8 @@ fn inject_impl_of_structural_trait(
             })
             .cloned(),
     );
+    // Mark as `automatically_derived` to avoid some silly lints.
+    attrs.push(cx.attribute(cx.meta_word(span, sym::automatically_derived)));
 
     let newitem = cx.item(
         span,
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index c7ea7de8f4e..bde0102186a 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -25,6 +25,7 @@ use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
 use rustc_expand::proc_macro::BangProcMacro;
 use rustc_span::symbol::sym;
 
+mod alloc_error_handler;
 mod assert;
 mod cfg;
 mod cfg_accessible;
@@ -94,6 +95,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
     }
 
     register_attr! {
+        alloc_error_handler: alloc_error_handler::expand,
         bench: test::expand_bench,
         cfg_accessible: cfg_accessible::Expander,
         cfg_eval: cfg_eval::expand,
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 705141614e2..fee5d04cdae 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -36,13 +36,22 @@ pub fn expand_test_case(
     let sp = ecx.with_def_site_ctxt(attr_sp);
     let mut item = anno_item.expect_item();
     item = item.map(|mut item| {
+        let test_path_symbol = Symbol::intern(&item_path(
+            // skip the name of the root module
+            &ecx.current_expansion.module.mod_path[1..],
+            &item.ident,
+        ));
         item.vis = ast::Visibility {
             span: item.vis.span,
             kind: ast::VisibilityKind::Public,
             tokens: None,
         };
         item.ident.span = item.ident.span.with_ctxt(sp.ctxt());
-        item.attrs.push(ecx.attribute(ecx.meta_word(sp, sym::rustc_test_marker)));
+        item.attrs.push(ecx.attribute(attr::mk_name_value_item_str(
+            Ident::new(sym::rustc_test_marker, sp),
+            test_path_symbol,
+            sp,
+        )));
         item
     });
 
@@ -215,6 +224,12 @@ pub fn expand_test_or_bench(
         )
     };
 
+    let test_path_symbol = Symbol::intern(&item_path(
+        // skip the name of the root module
+        &cx.current_expansion.module.mod_path[1..],
+        &item.ident,
+    ));
+
     let mut test_const = cx.item(
         sp,
         Ident::new(item.ident.name, sp),
@@ -224,9 +239,14 @@ pub fn expand_test_or_bench(
                 Ident::new(sym::cfg, attr_sp),
                 vec![attr::mk_nested_word_item(Ident::new(sym::test, attr_sp))],
             )),
-            // #[rustc_test_marker]
-            cx.attribute(cx.meta_word(attr_sp, sym::rustc_test_marker)),
-        ],
+            // #[rustc_test_marker = "test_case_sort_key"]
+            cx.attribute(attr::mk_name_value_item_str(
+                Ident::new(sym::rustc_test_marker, attr_sp),
+                test_path_symbol,
+                attr_sp,
+            )),
+        ]
+        .into(),
         // const $ident: test::TestDescAndFn =
         ast::ItemKind::Const(
             ast::Defaultness::Final,
@@ -250,14 +270,7 @@ pub fn expand_test_or_bench(
                                         cx.expr_call(
                                             sp,
                                             cx.expr_path(test_path("StaticTestName")),
-                                            vec![cx.expr_str(
-                                                sp,
-                                                Symbol::intern(&item_path(
-                                                    // skip the name of the root module
-                                                    &cx.current_expansion.module.mod_path[1..],
-                                                    &item.ident,
-                                                )),
-                                            )],
+                                            vec![cx.expr_str(sp, test_path_symbol)],
                                         ),
                                     ),
                                     // ignore: true | false
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 561ca00c719..b8b8351a36f 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -18,9 +18,11 @@ use thin_vec::thin_vec;
 
 use std::{iter, mem};
 
+#[derive(Clone)]
 struct Test {
     span: Span,
     ident: Ident,
+    name: Symbol,
 }
 
 struct TestCtxt<'a> {
@@ -120,10 +122,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
 
     fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         let mut item = i.into_inner();
-        if is_test_case(&self.cx.ext_cx.sess, &item) {
+        if let Some(name) = get_test_name(&self.cx.ext_cx.sess, &item) {
             debug!("this is a test item");
 
-            let test = Test { span: item.span, ident: item.ident };
+            let test = Test { span: item.span, ident: item.ident, name };
             self.tests.push(test);
         }
 
@@ -357,9 +359,12 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
     debug!("building test vector from {} tests", cx.test_cases.len());
     let ecx = &cx.ext_cx;
 
+    let mut tests = cx.test_cases.clone();
+    tests.sort_by(|a, b| a.name.as_str().cmp(&b.name.as_str()));
+
     ecx.expr_array_ref(
         sp,
-        cx.test_cases
+        tests
             .iter()
             .map(|test| {
                 ecx.expr_addr_of(test.span, ecx.expr_path(ecx.path(test.span, vec![test.ident])))
@@ -368,8 +373,8 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
     )
 }
 
-fn is_test_case(sess: &Session, i: &ast::Item) -> bool {
-    sess.contains_name(&i.attrs, sym::rustc_test_marker)
+fn get_test_name(sess: &Session, i: &ast::Item) -> Option<Symbol> {
+    sess.first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
 }
 
 fn get_test_runner(
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index e8897e9ae81..5061010c86c 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -29,7 +29,11 @@ jobs:
       matrix:
         include:
           - os: ubuntu-latest
+            env:
+              TARGET_TRIPLE: x86_64-unknown-linux-gnu
           - os: macos-latest
+            env:
+              TARGET_TRIPLE: x86_64-apple-darwin
           # cross-compile from Linux to Windows using mingw
           - os: ubuntu-latest
             env:
@@ -112,7 +116,7 @@ jobs:
       if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
       uses: actions/upload-artifact@v2
       with:
-        name: cg_clif-${{ runner.os }}
+        name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
         path: cg_clif.tar.xz
 
     - name: Upload prebuilt cg_clif (cross compile)
@@ -122,56 +126,89 @@ jobs:
         name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
         path: cg_clif.tar.xz
 
-  build_windows:
-    runs-on: windows-latest
+  windows:
+    runs-on: ${{ matrix.os }}
     timeout-minutes: 60
 
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          # Native Windows build with MSVC
+          - os: windows-latest
+            env:
+              TARGET_TRIPLE: x86_64-pc-windows-msvc
+          # cross-compile from Windows to Windows MinGW
+          - os: windows-latest
+            env:
+              TARGET_TRIPLE: x86_64-pc-windows-gnu
+
     steps:
     - uses: actions/checkout@v3
 
-    #- name: Cache cargo installed crates
-    #  uses: actions/cache@v2
-    #  with:
-    #    path: ~/.cargo/bin
-    #    key: ${{ runner.os }}-cargo-installed-crates
-
-    #- name: Cache cargo registry and index
-    #  uses: actions/cache@v2
-    #  with:
-    #    path: |
-    #        ~/.cargo/registry
-    #        ~/.cargo/git
-    #    key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
-
-    #- name: Cache cargo target dir
-    #  uses: actions/cache@v2
-    #  with:
-    #    path: target
-    #    key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+    - name: Cache cargo installed crates
+      uses: actions/cache@v2
+      with:
+        path: ~/.cargo/bin
+        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-installed-crates
+
+    - name: Cache cargo registry and index
+      uses: actions/cache@v2
+      with:
+        path: |
+            ~/.cargo/registry
+            ~/.cargo/git
+        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
+
+    - name: Cache cargo target dir
+      uses: actions/cache@v2
+      with:
+        path: target
+        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: Prepare dependencies
       run: |
         git config --global user.email "user@example.com"
         git config --global user.name "User"
         git config --global core.autocrlf false
-        rustup set default-host x86_64-pc-windows-gnu
         rustc y.rs -o y.exe -g
         ./y.exe prepare
 
+    - name: Build without unstable features
+      env:
+        TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
+      # This is the config rust-lang/rust uses for builds
+      run: ./y.rs build --no-unstable-features
+
     - name: Build
-      #name: Test
+      run: ./y.rs build --sysroot none
+
+    - name: Test
       run: |
         # Enable backtraces for easier debugging
-        #$Env:RUST_BACKTRACE=1
+        $Env:RUST_BACKTRACE=1
 
         # Reduce amount of benchmark runs as they are slow
-        #$Env:COMPILE_RUNS=2
-        #$Env:RUN_RUNS=2
+        $Env:COMPILE_RUNS=2
+        $Env:RUN_RUNS=2
 
         # Enable extra checks
-        #$Env:CG_CLIF_ENABLE_VERIFIER=1
-
-        ./y.exe build
+        $Env:CG_CLIF_ENABLE_VERIFIER=1
+        
+        # WIP Disable some tests
+        
+        # This fails due to some weird argument handling by hyperfine, not an actual regression
+        # more of a build system issue
+        (Get-Content config.txt) -replace '(bench.simple-raytracer)', '# $1' |  Out-File config.txt
+        
+        # This fails with a different output than expected 
+        (Get-Content config.txt) -replace '(test.regex-shootout-regex-dna)', '# $1' |  Out-File config.txt
+
+        ./y.exe test
 
     - name: Package prebuilt cg_clif
       # don't use compression as xzip isn't supported by tar on windows and bzip2 hangs
@@ -180,5 +217,5 @@ jobs:
     - name: Upload prebuilt cg_clif
       uses: actions/upload-artifact@v2
       with:
-        name: cg_clif-${{ runner.os }}
+        name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
         path: cg_clif.tar
diff --git a/compiler/rustc_codegen_cranelift/.gitignore b/compiler/rustc_codegen_cranelift/.gitignore
index 6fd3e4443de..fae09592c6a 100644
--- a/compiler/rustc_codegen_cranelift/.gitignore
+++ b/compiler/rustc_codegen_cranelift/.gitignore
@@ -15,8 +15,4 @@ perf.data.old
 /build_sysroot/compiler-builtins
 /build_sysroot/rustc_version
 /rust
-/rand
-/regex
-/simple-raytracer
-/portable-simd
-/abi-checker
+/download
diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json
index d88309e412e..13301bf20a5 100644
--- a/compiler/rustc_codegen_cranelift/.vscode/settings.json
+++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json
@@ -7,7 +7,7 @@
     "rust-analyzer.cargo.features": ["unstable-features"],
     "rust-analyzer.linkedProjects": [
         "./Cargo.toml",
-        //"./build_sysroot/sysroot_src/src/libstd/Cargo.toml",
+        //"./build_sysroot/sysroot_src/library/std/Cargo.toml",
         {
             "roots": [
                 "./example/mini_core.rs",
@@ -36,10 +36,10 @@
             ]
         },
         {
-            "roots": ["./scripts/filter_profile.rs"],
+            "roots": ["./example/std_example.rs"],
             "crates": [
                 {
-                    "root_module": "./scripts/filter_profile.rs",
+                    "root_module": "./example/std_example.rs",
                     "edition": "2018",
                     "deps": [{ "crate": 1, "name": "std" }],
                     "cfg": [],
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index edae7e47157..3fa9d56cd01 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -25,6 +25,12 @@ version = "0.8.0"
 source = "git+https://github.com/bjorn3/rust-ar.git?branch=do_not_remove_cg_clif_ranlib#de9ab0e56bf3a208381d342aa5b60f9ff2891648"
 
 [[package]]
+name = "arrayvec"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
+
+[[package]]
 name = "autocfg"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -37,6 +43,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
+name = "bumpalo"
+version = "3.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
+
+[[package]]
 name = "byteorder"
 version = "1.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -50,19 +62,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.87.0"
+version = "0.88.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93945adbccc8d731503d3038814a51e8317497c9e205411820348132fa01a358"
+checksum = "44409ccf2d0f663920cab563d2b79fcd6b2e9a2bcc6e929fef76c8f82ad6c17a"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.87.0"
+version = "0.88.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b482acc9d0d0d1ad3288a90a8150ee648be3dce8dc8c8669ff026f72debdc31"
+checksum = "98de2018ad96eb97f621f7d6b900a0cc661aec8d02ea4a50e56ecb48e5a2fcaf"
 dependencies = [
+ "arrayvec",
+ "bumpalo",
  "cranelift-bforest",
  "cranelift-codegen-meta",
  "cranelift-codegen-shared",
@@ -77,30 +91,30 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.87.0"
+version = "0.88.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9ec188d71e663192ef9048f204e410a7283b609942efc9fcc77da6d496edbb8"
+checksum = "5287ce36e6c4758fbaf298bd1a8697ad97a4f2375a3d1b61142ea538db4877e5"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.87.0"
+version = "0.88.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ad794b1b1c2c7bd9f7b76cfe0f084eaf7753e55d56191c3f7d89e8fa4978b99"
+checksum = "2855c24219e2f08827f3f4ffb2da92e134ae8d8ecc185b11ec8f9878cf5f588e"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.87.0"
+version = "0.88.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "342da0d5056f4119d3c311c4aab2460ceb6ee6e127bb395b76dd2279a09ea7a5"
+checksum = "0b65673279d75d34bf11af9660ae2dbd1c22e6d28f163f5c72f4e1dc56d56103"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.87.0"
+version = "0.88.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfff792f775b07d4d9cfe9f1c767ce755c6cbadda1bbd6db18a1c75ff9f7376a"
+checksum = "3ed2b3d7a4751163f6c4a349205ab1b7d9c00eecf19dcea48592ef1f7688eefc"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -110,15 +124,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.87.0"
+version = "0.88.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d51089478849f2ac8ef60a8a2d5346c8d4abfec0e45ac5b24530ef9f9499e1e"
+checksum = "3be64cecea9d90105fc6a2ba2d003e98c867c1d6c4c86cc878f97ad9fb916293"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.87.0"
+version = "0.88.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "095936e41720f86004b4c57ce88e6a13af28646bb3a6fb4afbebd5ae90c50029"
+checksum = "f98ed42a70a0c9c388e34ec9477f57fc7300f541b1e5136a0e2ea02b1fac6015"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -134,9 +148,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.87.0"
+version = "0.88.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "704a1aea4723d97eafe0fb7af110f6f6868b1ac95f5380bbc9adb2a3b8cf97e8"
+checksum = "d658ac7f156708bfccb647216cc8b9387469f50d352ba4ad80150541e4ae2d49"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -144,9 +158,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.87.0"
+version = "0.88.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "885debe62f2078638d6585f54c9f05f5c2008f22ce5a2a9100ada785fc065dbd"
+checksum = "c4a03a6ac1b063e416ca4b93f6247978c991475e8271465340caa6f92f3c16a4"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -155,9 +169,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.87.0"
+version = "0.88.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aac1310cf1081ae8eca916c92cd163b977c77cab6e831fa812273c26ff921816"
+checksum = "eef0b4119b645b870a43a036d76c0ada3a076b1f82e8b8487659304c8b09049b"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -232,9 +246,9 @@ checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b"
 
 [[package]]
 name = "libloading"
-version = "0.6.7"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883"
+checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
 dependencies = [
  "cfg-if",
  "winapi",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index e7c34274854..09cf5b4a1ed 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -8,19 +8,19 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.87.0", features = ["unwind", "all-arch"] }
-cranelift-frontend = "0.87.0"
-cranelift-module = "0.87.0"
-cranelift-native = "0.87.0"
-cranelift-jit = { version = "0.87.0", optional = true }
-cranelift-object = "0.87.0"
+cranelift-codegen = { version = "0.88.1", features = ["unwind", "all-arch"] }
+cranelift-frontend = "0.88.1"
+cranelift-module = "0.88.1"
+cranelift-native = "0.88.1"
+cranelift-jit = { version = "0.88.1", optional = true }
+cranelift-object = "0.88.1"
 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"] }
 
 ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
 indexmap = "1.9.1"
-libloading = { version = "0.6.0", optional = true }
+libloading = { version = "0.7.3", optional = true }
 once_cell = "1.10.0"
 smallvec = "1.8.1"
 
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
index 6c5043bb6f8..f6a9cb67290 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
@@ -55,10 +55,20 @@ dependencies = [
 ]
 
 [[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+dependencies = [
+ "compiler_builtins",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
 name = "compiler_builtins"
-version = "0.1.79"
+version = "0.1.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f873ce2bd3550b0b565f878b3d04ea8253f4259dc3d20223af2e1ba86f5ecca"
+checksum = "18cd7635fea7bb481ea543b392789844c1ad581299da70184c7175ce3af76603"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -123,9 +133,9 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "897cd85af6387be149f55acf168e41be176a02de7872403aaab184afc2f327e6"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
 dependencies = [
  "compiler_builtins",
  "libc",
@@ -135,9 +145,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.132"
+version = "0.2.135"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
+checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -182,7 +192,7 @@ name = "panic_abort"
 version = "0.0.0"
 dependencies = [
  "alloc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "libc",
@@ -193,7 +203,7 @@ name = "panic_unwind"
 version = "0.0.0"
 dependencies = [
  "alloc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "libc",
@@ -245,7 +255,7 @@ version = "0.0.0"
 dependencies = [
  "addr2line",
  "alloc",
- "cfg-if",
+ "cfg-if 1.0.0",
  "compiler_builtins",
  "core",
  "dlmalloc",
@@ -267,7 +277,7 @@ dependencies = [
 name = "std_detect"
 version = "0.1.5"
 dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
  "compiler_builtins",
  "libc",
  "rustc-std-workspace-alloc",
@@ -289,7 +299,7 @@ dependencies = [
 name = "test"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "core",
  "getopts",
  "libc",
@@ -301,9 +311,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-width"
-version = "0.1.9"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
@@ -315,7 +325,7 @@ name = "unwind"
 version = "0.0.0"
 dependencies = [
  "cc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "libc",
diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
new file mode 100644
index 00000000000..fae5b271636
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
@@ -0,0 +1,52 @@
+use std::env;
+use std::path::Path;
+
+use super::build_sysroot;
+use super::config;
+use super::prepare;
+use super::utils::{cargo_command, spawn_and_wait};
+use super::SysrootKind;
+
+pub(crate) fn run(
+    channel: &str,
+    sysroot_kind: SysrootKind,
+    target_dir: &Path,
+    cg_clif_dylib: &Path,
+    host_triple: &str,
+    target_triple: &str,
+) {
+    if !config::get_bool("testsuite.abi-cafe") {
+        eprintln!("[SKIP] abi-cafe");
+        return;
+    }
+
+    if host_triple != target_triple {
+        eprintln!("[SKIP] abi-cafe (cross-compilation not supported)");
+        return;
+    }
+
+    eprintln!("Building sysroot for abi-cafe");
+    build_sysroot::build_sysroot(
+        channel,
+        sysroot_kind,
+        target_dir,
+        cg_clif_dylib,
+        host_triple,
+        target_triple,
+    );
+
+    eprintln!("Running abi-cafe");
+    let abi_cafe_path = prepare::ABI_CAFE.source_dir();
+    env::set_current_dir(abi_cafe_path.clone()).unwrap();
+
+    let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
+
+    let mut cmd = cargo_command("cargo", "run", Some(target_triple), &abi_cafe_path);
+    cmd.arg("--");
+    cmd.arg("--pairs");
+    cmd.args(pairs);
+    cmd.arg("--add-rustc-codegen-backend");
+    cmd.arg(format!("cgclif:{}", cg_clif_dylib.display()));
+
+    spawn_and_wait(cmd);
+}
diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_checker.rs b/compiler/rustc_codegen_cranelift/build_system/abi_checker.rs
deleted file mode 100644
index 67dbd0a38a4..00000000000
--- a/compiler/rustc_codegen_cranelift/build_system/abi_checker.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-use super::build_sysroot;
-use super::config;
-use super::utils::spawn_and_wait;
-use build_system::SysrootKind;
-use std::env;
-use std::path::Path;
-use std::process::Command;
-
-pub(crate) fn run(
-    channel: &str,
-    sysroot_kind: SysrootKind,
-    target_dir: &Path,
-    cg_clif_build_dir: &Path,
-    host_triple: &str,
-    target_triple: &str,
-) {
-    if !config::get_bool("testsuite.abi-checker") {
-        eprintln!("[SKIP] abi-checker");
-        return;
-    }
-
-    if host_triple != target_triple {
-        eprintln!("[SKIP] abi-checker (cross-compilation not supported)");
-        return;
-    }
-
-    eprintln!("Building sysroot for abi-checker");
-    build_sysroot::build_sysroot(
-        channel,
-        sysroot_kind,
-        target_dir,
-        cg_clif_build_dir,
-        host_triple,
-        target_triple,
-    );
-
-    eprintln!("Running abi-checker");
-    let mut abi_checker_path = env::current_dir().unwrap();
-    abi_checker_path.push("abi-checker");
-    env::set_current_dir(abi_checker_path.clone()).unwrap();
-
-    let build_dir = abi_checker_path.parent().unwrap().join("build");
-    let cg_clif_dylib_path = build_dir.join(if cfg!(windows) { "bin" } else { "lib" }).join(
-        env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
-    );
-
-    let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
-
-    let mut cmd = Command::new("cargo");
-    cmd.arg("run");
-    cmd.arg("--target");
-    cmd.arg(target_triple);
-    cmd.arg("--");
-    cmd.arg("--pairs");
-    cmd.args(pairs);
-    cmd.arg("--add-rustc-codegen-backend");
-    cmd.arg(format!("cgclif:{}", cg_clif_dylib_path.display()));
-
-    spawn_and_wait(cmd);
-}
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
index 9e59b8199b4..cda468bcfa2 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
@@ -1,16 +1,16 @@
 use std::env;
-use std::path::{Path, PathBuf};
-use std::process::Command;
+use std::path::PathBuf;
 
-use super::utils::is_ci;
+use super::rustc_info::get_file_name;
+use super::utils::{cargo_command, is_ci};
 
 pub(crate) fn build_backend(
     channel: &str,
     host_triple: &str,
     use_unstable_features: bool,
 ) -> PathBuf {
-    let mut cmd = Command::new("cargo");
-    cmd.arg("build").arg("--target").arg(host_triple);
+    let source_dir = std::env::current_dir().unwrap();
+    let mut cmd = cargo_command("cargo", "build", Some(host_triple), &source_dir);
 
     cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode
 
@@ -41,5 +41,9 @@ pub(crate) fn build_backend(
     eprintln!("[BUILD] rustc_codegen_cranelift");
     super::utils::spawn_and_wait(cmd);
 
-    Path::new("target").join(host_triple).join(channel)
+    source_dir
+        .join("target")
+        .join(host_triple)
+        .join(channel)
+        .join(get_file_name("rustc_codegen_cranelift", "dylib"))
 }
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
index 7e205b0fd0b..856aecc49fd 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
@@ -3,14 +3,14 @@ use std::path::{Path, PathBuf};
 use std::process::{self, Command};
 
 use super::rustc_info::{get_file_name, get_rustc_version, get_wrapper_file_name};
-use super::utils::{spawn_and_wait, try_hard_link};
+use super::utils::{cargo_command, spawn_and_wait, try_hard_link};
 use super::SysrootKind;
 
 pub(crate) fn build_sysroot(
     channel: &str,
     sysroot_kind: SysrootKind,
     target_dir: &Path,
-    cg_clif_build_dir: &Path,
+    cg_clif_dylib_src: &Path,
     host_triple: &str,
     target_triple: &str,
 ) {
@@ -23,7 +23,6 @@ pub(crate) fn build_sysroot(
     fs::create_dir_all(target_dir.join("lib")).unwrap();
 
     // Copy the backend
-    let cg_clif_dylib = get_file_name("rustc_codegen_cranelift", "dylib");
     let cg_clif_dylib_path = target_dir
         .join(if cfg!(windows) {
             // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
@@ -32,8 +31,8 @@ pub(crate) fn build_sysroot(
         } else {
             "lib"
         })
-        .join(&cg_clif_dylib);
-    try_hard_link(cg_clif_build_dir.join(cg_clif_dylib), &cg_clif_dylib_path);
+        .join(get_file_name("rustc_codegen_cranelift", "dylib"));
+    try_hard_link(cg_clif_dylib_src, &cg_clif_dylib_path);
 
     // Build and copy rustc and cargo wrappers
     for wrapper in ["rustc-clif", "cargo-clif"] {
@@ -186,10 +185,10 @@ fn build_clif_sysroot_for_triple(
     }
 
     // Build sysroot
-    let mut build_cmd = Command::new("cargo");
-    build_cmd.arg("build").arg("--target").arg(triple).current_dir("build_sysroot");
+    let mut build_cmd = cargo_command("cargo", "build", Some(triple), Path::new("build_sysroot"));
     let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
     rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap()));
+    rustflags.push_str(&format!(" --sysroot={}", target_dir.to_str().unwrap()));
     if channel == "release" {
         build_cmd.arg("--release");
         rustflags.push_str(" -Zmir-opt-level=3");
diff --git a/compiler/rustc_codegen_cranelift/build_system/config.rs b/compiler/rustc_codegen_cranelift/build_system/config.rs
index ef540cf1f82..c31784e1097 100644
--- a/compiler/rustc_codegen_cranelift/build_system/config.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/config.rs
@@ -1,4 +1,5 @@
-use std::{fs, process};
+use std::fs;
+use std::process;
 
 fn load_config_file() -> Vec<(String, Option<String>)> {
     fs::read_to_string("config.txt")
diff --git a/compiler/rustc_codegen_cranelift/build_system/mod.rs b/compiler/rustc_codegen_cranelift/build_system/mod.rs
index c3706dc6f82..b25270d832c 100644
--- a/compiler/rustc_codegen_cranelift/build_system/mod.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/mod.rs
@@ -4,7 +4,7 @@ use std::process;
 
 use self::utils::is_ci;
 
-mod abi_checker;
+mod abi_cafe;
 mod build_backend;
 mod build_sysroot;
 mod config;
@@ -122,32 +122,23 @@ pub fn main() {
         host_triple.clone()
     };
 
-    if target_triple.ends_with("-msvc") {
-        eprintln!("The MSVC toolchain is not yet supported by rustc_codegen_cranelift.");
-        eprintln!("Switch to the MinGW toolchain for Windows support.");
-        eprintln!("Hint: You can use `rustup set default-host x86_64-pc-windows-gnu` to");
-        eprintln!("set the global default target to MinGW");
-        process::exit(1);
-    }
-
-    let cg_clif_build_dir =
-        build_backend::build_backend(channel, &host_triple, use_unstable_features);
+    let cg_clif_dylib = build_backend::build_backend(channel, &host_triple, use_unstable_features);
     match command {
         Command::Test => {
             tests::run_tests(
                 channel,
                 sysroot_kind,
                 &target_dir,
-                &cg_clif_build_dir,
+                &cg_clif_dylib,
                 &host_triple,
                 &target_triple,
             );
 
-            abi_checker::run(
+            abi_cafe::run(
                 channel,
                 sysroot_kind,
                 &target_dir,
-                &cg_clif_build_dir,
+                &cg_clif_dylib,
                 &host_triple,
                 &target_triple,
             );
@@ -157,7 +148,7 @@ pub fn main() {
                 channel,
                 sysroot_kind,
                 &target_dir,
-                &cg_clif_build_dir,
+                &cg_clif_dylib,
                 &host_triple,
                 &target_triple,
             );
diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
index d23b7f00dcf..3111f62f6c2 100644
--- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
@@ -1,64 +1,63 @@
 use std::env;
 use std::ffi::OsStr;
-use std::ffi::OsString;
 use std::fs;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use std::process::Command;
 
 use super::rustc_info::{get_file_name, get_rustc_path, get_rustc_version};
-use super::utils::{copy_dir_recursively, spawn_and_wait};
+use super::utils::{cargo_command, copy_dir_recursively, spawn_and_wait};
+
+pub(crate) const ABI_CAFE: GitRepo =
+    GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
+
+pub(crate) const RAND: GitRepo =
+    GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
+
+pub(crate) const REGEX: GitRepo =
+    GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
+
+pub(crate) const PORTABLE_SIMD: GitRepo = GitRepo::github(
+    "rust-lang",
+    "portable-simd",
+    "d5cd4a8112d958bd3a252327e0d069a6363249bd",
+    "portable-simd",
+);
+
+pub(crate) const SIMPLE_RAYTRACER: GitRepo = GitRepo::github(
+    "ebobby",
+    "simple-raytracer",
+    "804a7a21b9e673a482797aa289a18ed480e4d813",
+    "<none>",
+);
 
 pub(crate) fn prepare() {
+    if Path::new("download").exists() {
+        std::fs::remove_dir_all(Path::new("download")).unwrap();
+    }
+    std::fs::create_dir_all(Path::new("download")).unwrap();
+
     prepare_sysroot();
 
+    // FIXME maybe install this only locally?
     eprintln!("[INSTALL] hyperfine");
     Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap();
 
-    clone_repo_shallow_github(
-        "abi-checker",
-        "Gankra",
-        "abi-checker",
-        "a2232d45f202846f5c02203c9f27355360f9a2ff",
-    );
-    apply_patches("abi-checker", Path::new("abi-checker"));
-
-    clone_repo_shallow_github(
-        "rand",
-        "rust-random",
-        "rand",
-        "0f933f9c7176e53b2a3c7952ded484e1783f0bf1",
-    );
-    apply_patches("rand", Path::new("rand"));
-
-    clone_repo_shallow_github(
-        "regex",
-        "rust-lang",
-        "regex",
-        "341f207c1071f7290e3f228c710817c280c8dca1",
-    );
-
-    clone_repo_shallow_github(
-        "portable-simd",
-        "rust-lang",
-        "portable-simd",
-        "b8d6b6844602f80af79cd96401339ec594d472d8",
-    );
-    apply_patches("portable-simd", Path::new("portable-simd"));
-
-    clone_repo_shallow_github(
-        "simple-raytracer",
-        "ebobby",
-        "simple-raytracer",
-        "804a7a21b9e673a482797aa289a18ed480e4d813",
-    );
+    ABI_CAFE.fetch();
+    RAND.fetch();
+    REGEX.fetch();
+    PORTABLE_SIMD.fetch();
+    SIMPLE_RAYTRACER.fetch();
 
     eprintln!("[LLVM BUILD] simple-raytracer");
-    let mut build_cmd = Command::new("cargo");
-    build_cmd.arg("build").env_remove("CARGO_TARGET_DIR").current_dir("simple-raytracer");
+    let build_cmd = cargo_command("cargo", "build", None, &SIMPLE_RAYTRACER.source_dir());
     spawn_and_wait(build_cmd);
     fs::copy(
-        Path::new("simple-raytracer/target/debug").join(get_file_name("main", "bin")),
-        Path::new("simple-raytracer").join(get_file_name("raytracer_cg_llvm", "bin")),
+        SIMPLE_RAYTRACER
+            .source_dir()
+            .join("target")
+            .join("debug")
+            .join(get_file_name("main", "bin")),
+        SIMPLE_RAYTRACER.source_dir().join(get_file_name("raytracer_cg_llvm", "bin")),
     )
     .unwrap();
 }
@@ -90,38 +89,78 @@ fn prepare_sysroot() {
     apply_patches("sysroot", &sysroot_src);
 }
 
+pub(crate) struct GitRepo {
+    url: GitRepoUrl,
+    rev: &'static str,
+    patch_name: &'static str,
+}
+
+enum GitRepoUrl {
+    Github { user: &'static str, repo: &'static str },
+}
+
+impl GitRepo {
+    const fn github(
+        user: &'static str,
+        repo: &'static str,
+        rev: &'static str,
+        patch_name: &'static str,
+    ) -> GitRepo {
+        GitRepo { url: GitRepoUrl::Github { user, repo }, rev, patch_name }
+    }
+
+    pub(crate) fn source_dir(&self) -> PathBuf {
+        match self.url {
+            GitRepoUrl::Github { user: _, repo } => {
+                std::env::current_dir().unwrap().join("download").join(repo)
+            }
+        }
+    }
+
+    fn fetch(&self) {
+        match self.url {
+            GitRepoUrl::Github { user, repo } => {
+                clone_repo_shallow_github(&self.source_dir(), user, repo, self.rev);
+            }
+        }
+        apply_patches(self.patch_name, &self.source_dir());
+    }
+}
+
 #[allow(dead_code)]
-fn clone_repo(target_dir: &str, repo: &str, rev: &str) {
+fn clone_repo(download_dir: &Path, repo: &str, rev: &str) {
     eprintln!("[CLONE] {}", repo);
     // Ignore exit code as the repo may already have been checked out
-    Command::new("git").arg("clone").arg(repo).arg(target_dir).spawn().unwrap().wait().unwrap();
+    Command::new("git").arg("clone").arg(repo).arg(&download_dir).spawn().unwrap().wait().unwrap();
 
     let mut clean_cmd = Command::new("git");
-    clean_cmd.arg("checkout").arg("--").arg(".").current_dir(target_dir);
+    clean_cmd.arg("checkout").arg("--").arg(".").current_dir(&download_dir);
     spawn_and_wait(clean_cmd);
 
     let mut checkout_cmd = Command::new("git");
-    checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(target_dir);
+    checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(download_dir);
     spawn_and_wait(checkout_cmd);
 }
 
-fn clone_repo_shallow_github(target_dir: &str, username: &str, repo: &str, rev: &str) {
+fn clone_repo_shallow_github(download_dir: &Path, user: &str, repo: &str, rev: &str) {
     if cfg!(windows) {
         // Older windows doesn't have tar or curl by default. Fall back to using git.
-        clone_repo(target_dir, &format!("https://github.com/{}/{}.git", username, repo), rev);
+        clone_repo(download_dir, &format!("https://github.com/{}/{}.git", user, repo), rev);
         return;
     }
 
-    let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", username, repo, rev);
-    let archive_file = format!("{}.tar.gz", rev);
-    let archive_dir = format!("{}-{}", repo, rev);
+    let downloads_dir = std::env::current_dir().unwrap().join("download");
+
+    let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", user, repo, rev);
+    let archive_file = downloads_dir.join(format!("{}.tar.gz", rev));
+    let archive_dir = downloads_dir.join(format!("{}-{}", repo, rev));
 
-    eprintln!("[DOWNLOAD] {}/{} from {}", username, repo, archive_url);
+    eprintln!("[DOWNLOAD] {}/{} from {}", user, repo, archive_url);
 
     // Remove previous results if they exists
     let _ = std::fs::remove_file(&archive_file);
     let _ = std::fs::remove_dir_all(&archive_dir);
-    let _ = std::fs::remove_dir_all(target_dir);
+    let _ = std::fs::remove_dir_all(&download_dir);
 
     // Download zip archive
     let mut download_cmd = Command::new("curl");
@@ -130,13 +169,13 @@ fn clone_repo_shallow_github(target_dir: &str, username: &str, repo: &str, rev:
 
     // Unpack tar archive
     let mut unpack_cmd = Command::new("tar");
-    unpack_cmd.arg("xf").arg(&archive_file);
+    unpack_cmd.arg("xf").arg(&archive_file).current_dir(downloads_dir);
     spawn_and_wait(unpack_cmd);
 
     // Rename unpacked dir to the expected name
-    std::fs::rename(archive_dir, target_dir).unwrap();
+    std::fs::rename(archive_dir, &download_dir).unwrap();
 
-    init_git_repo(Path::new(target_dir));
+    init_git_repo(&download_dir);
 
     // Cleanup
     std::fs::remove_file(archive_file).unwrap();
@@ -156,14 +195,20 @@ fn init_git_repo(repo_dir: &Path) {
     spawn_and_wait(git_commit_cmd);
 }
 
-fn get_patches(crate_name: &str) -> Vec<OsString> {
-    let mut patches: Vec<_> = fs::read_dir("patches")
+fn get_patches(source_dir: &Path, crate_name: &str) -> Vec<PathBuf> {
+    let mut patches: Vec<_> = fs::read_dir(source_dir.join("patches"))
         .unwrap()
         .map(|entry| entry.unwrap().path())
         .filter(|path| path.extension() == Some(OsStr::new("patch")))
-        .map(|path| path.file_name().unwrap().to_owned())
-        .filter(|file_name| {
-            file_name.to_str().unwrap().split_once("-").unwrap().1.starts_with(crate_name)
+        .filter(|path| {
+            path.file_name()
+                .unwrap()
+                .to_str()
+                .unwrap()
+                .split_once("-")
+                .unwrap()
+                .1
+                .starts_with(crate_name)
         })
         .collect();
     patches.sort();
@@ -171,11 +216,18 @@ fn get_patches(crate_name: &str) -> Vec<OsString> {
 }
 
 fn apply_patches(crate_name: &str, target_dir: &Path) {
-    for patch in get_patches(crate_name) {
-        eprintln!("[PATCH] {:?} <- {:?}", target_dir.file_name().unwrap(), patch);
-        let patch_arg = env::current_dir().unwrap().join("patches").join(patch);
+    if crate_name == "<none>" {
+        return;
+    }
+
+    for patch in get_patches(&std::env::current_dir().unwrap(), crate_name) {
+        eprintln!(
+            "[PATCH] {:?} <- {:?}",
+            target_dir.file_name().unwrap(),
+            patch.file_name().unwrap()
+        );
         let mut apply_patch_cmd = Command::new("git");
-        apply_patch_cmd.arg("am").arg(patch_arg).arg("-q").current_dir(target_dir);
+        apply_patch_cmd.arg("am").arg(patch).arg("-q").current_dir(target_dir);
         spawn_and_wait(apply_patch_cmd);
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs b/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs
index 913b589afcc..3c08b6fa389 100644
--- a/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs
@@ -65,7 +65,7 @@ pub(crate) fn get_file_name(crate_name: &str, crate_type: &str) -> String {
 }
 
 /// Similar to `get_file_name`, but converts any dashes (`-`) in the `crate_name` to
-/// underscores (`_`). This is specially made for the the rustc and cargo wrappers
+/// underscores (`_`). This is specially made for the rustc and cargo wrappers
 /// which have a dash in the name, and that is not allowed in a crate name.
 pub(crate) fn get_wrapper_file_name(crate_name: &str, crate_type: &str) -> String {
     let crate_name = crate_name.replace('-', "_");
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index e21397cece8..a414b60f4e0 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -1,7 +1,8 @@
 use super::build_sysroot;
 use super::config;
+use super::prepare;
 use super::rustc_info::get_wrapper_file_name;
-use super::utils::{spawn_and_wait, spawn_and_wait_with_input};
+use super::utils::{cargo_command, hyperfine_command, spawn_and_wait, spawn_and_wait_with_input};
 use build_system::SysrootKind;
 use std::env;
 use std::ffi::OsStr;
@@ -217,103 +218,95 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
 
 const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
     TestCase::new("test.rust-random/rand", &|runner| {
-        runner.in_dir(["rand"], |runner| {
-            runner.run_cargo(["clean"]);
+        runner.in_dir(prepare::RAND.source_dir(), |runner| {
+            runner.run_cargo("clean", []);
 
             if runner.host_triple == runner.target_triple {
                 eprintln!("[TEST] rust-random/rand");
-                runner.run_cargo(["test", "--workspace"]);
+                runner.run_cargo("test", ["--workspace"]);
             } else {
                 eprintln!("[AOT] rust-random/rand");
-                runner.run_cargo([
-                    "build",
-                    "--workspace",
-                    "--target",
-                    &runner.target_triple,
-                    "--tests",
-                ]);
+                runner.run_cargo("build", ["--workspace", "--tests"]);
             }
         });
     }),
     TestCase::new("bench.simple-raytracer", &|runner| {
-        runner.in_dir(["simple-raytracer"], |runner| {
-            let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string());
+        runner.in_dir(prepare::SIMPLE_RAYTRACER.source_dir(), |runner| {
+            let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap();
 
             if runner.host_triple == runner.target_triple {
                 eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
-                let mut bench_compile = Command::new("hyperfine");
-                bench_compile.arg("--runs");
-                bench_compile.arg(&run_runs);
-                bench_compile.arg("--warmup");
-                bench_compile.arg("1");
-                bench_compile.arg("--prepare");
-                bench_compile.arg(format!("{:?}", runner.cargo_command(["clean"])));
-
-                if cfg!(windows) {
-                    bench_compile.arg("cmd /C \"set RUSTFLAGS= && cargo build\"");
-                } else {
-                    bench_compile.arg("RUSTFLAGS='' cargo build");
-                }
+                let prepare = runner.cargo_command("clean", []);
+
+                let llvm_build_cmd = cargo_command("cargo", "build", None, Path::new("."));
+
+                let cargo_clif = runner
+                    .root_dir
+                    .clone()
+                    .join("build")
+                    .join(get_wrapper_file_name("cargo-clif", "bin"));
+                let clif_build_cmd = cargo_command(cargo_clif, "build", None, Path::new("."));
+
+                let bench_compile =
+                    hyperfine_command(1, run_runs, Some(prepare), llvm_build_cmd, clif_build_cmd);
 
-                bench_compile.arg(format!("{:?}", runner.cargo_command(["build"])));
                 spawn_and_wait(bench_compile);
 
                 eprintln!("[BENCH RUN] ebobby/simple-raytracer");
                 fs::copy(PathBuf::from("./target/debug/main"), PathBuf::from("raytracer_cg_clif"))
                     .unwrap();
 
-                let mut bench_run = Command::new("hyperfine");
-                bench_run.arg("--runs");
-                bench_run.arg(&run_runs);
-                bench_run.arg(PathBuf::from("./raytracer_cg_llvm"));
-                bench_run.arg(PathBuf::from("./raytracer_cg_clif"));
+                let bench_run = hyperfine_command(
+                    0,
+                    run_runs,
+                    None,
+                    Command::new("./raytracer_cg_llvm"),
+                    Command::new("./raytracer_cg_clif"),
+                );
                 spawn_and_wait(bench_run);
             } else {
-                runner.run_cargo(["clean"]);
+                runner.run_cargo("clean", []);
                 eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
                 eprintln!("[COMPILE] ebobby/simple-raytracer");
-                runner.run_cargo(["build", "--target", &runner.target_triple]);
+                runner.run_cargo("build", []);
                 eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
             }
         });
     }),
     TestCase::new("test.libcore", &|runner| {
-        runner.in_dir(["build_sysroot", "sysroot_src", "library", "core", "tests"], |runner| {
-            runner.run_cargo(["clean"]);
-
-            if runner.host_triple == runner.target_triple {
-                runner.run_cargo(["test"]);
-            } else {
-                eprintln!("Cross-Compiling: Not running tests");
-                runner.run_cargo(["build", "--target", &runner.target_triple, "--tests"]);
-            }
-        });
+        runner.in_dir(
+            std::env::current_dir()
+                .unwrap()
+                .join("build_sysroot")
+                .join("sysroot_src")
+                .join("library")
+                .join("core")
+                .join("tests"),
+            |runner| {
+                runner.run_cargo("clean", []);
+
+                if runner.host_triple == runner.target_triple {
+                    runner.run_cargo("test", []);
+                } else {
+                    eprintln!("Cross-Compiling: Not running tests");
+                    runner.run_cargo("build", ["--tests"]);
+                }
+            },
+        );
     }),
     TestCase::new("test.regex-shootout-regex-dna", &|runner| {
-        runner.in_dir(["regex"], |runner| {
-            runner.run_cargo(["clean"]);
+        runner.in_dir(prepare::REGEX.source_dir(), |runner| {
+            runner.run_cargo("clean", []);
 
             // newer aho_corasick versions throw a deprecation warning
             let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
 
-            let mut build_cmd = runner.cargo_command([
-                "build",
-                "--example",
-                "shootout-regex-dna",
-                "--target",
-                &runner.target_triple,
-            ]);
+            let mut build_cmd = runner.cargo_command("build", ["--example", "shootout-regex-dna"]);
             build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
             spawn_and_wait(build_cmd);
 
             if runner.host_triple == runner.target_triple {
-                let mut run_cmd = runner.cargo_command([
-                    "run",
-                    "--example",
-                    "shootout-regex-dna",
-                    "--target",
-                    &runner.target_triple,
-                ]);
+                let mut run_cmd = runner.cargo_command("run", ["--example", "shootout-regex-dna"]);
                 run_cmd.env("RUSTFLAGS", lint_rust_flags);
 
                 let input =
@@ -353,41 +346,43 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
         });
     }),
     TestCase::new("test.regex", &|runner| {
-        runner.in_dir(["regex"], |runner| {
-            runner.run_cargo(["clean"]);
+        runner.in_dir(prepare::REGEX.source_dir(), |runner| {
+            runner.run_cargo("clean", []);
 
             // newer aho_corasick versions throw a deprecation warning
             let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
 
             if runner.host_triple == runner.target_triple {
-                let mut run_cmd = runner.cargo_command([
+                let mut run_cmd = runner.cargo_command(
                     "test",
-                    "--tests",
-                    "--",
-                    "--exclude-should-panic",
-                    "--test-threads",
-                    "1",
-                    "-Zunstable-options",
-                    "-q",
-                ]);
+                    [
+                        "--tests",
+                        "--",
+                        "--exclude-should-panic",
+                        "--test-threads",
+                        "1",
+                        "-Zunstable-options",
+                        "-q",
+                    ],
+                );
                 run_cmd.env("RUSTFLAGS", lint_rust_flags);
                 spawn_and_wait(run_cmd);
             } else {
                 eprintln!("Cross-Compiling: Not running tests");
                 let mut build_cmd =
-                    runner.cargo_command(["build", "--tests", "--target", &runner.target_triple]);
+                    runner.cargo_command("build", ["--tests", "--target", &runner.target_triple]);
                 build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
                 spawn_and_wait(build_cmd);
             }
         });
     }),
     TestCase::new("test.portable-simd", &|runner| {
-        runner.in_dir(["portable-simd"], |runner| {
-            runner.run_cargo(["clean"]);
-            runner.run_cargo(["build", "--all-targets", "--target", &runner.target_triple]);
+        runner.in_dir(prepare::PORTABLE_SIMD.source_dir(), |runner| {
+            runner.run_cargo("clean", []);
+            runner.run_cargo("build", ["--all-targets", "--target", &runner.target_triple]);
 
             if runner.host_triple == runner.target_triple {
-                runner.run_cargo(["test", "-q"]);
+                runner.run_cargo("test", ["-q"]);
             }
         });
     }),
@@ -397,7 +392,7 @@ pub(crate) fn run_tests(
     channel: &str,
     sysroot_kind: SysrootKind,
     target_dir: &Path,
-    cg_clif_build_dir: &Path,
+    cg_clif_dylib: &Path,
     host_triple: &str,
     target_triple: &str,
 ) {
@@ -408,7 +403,7 @@ pub(crate) fn run_tests(
             channel,
             SysrootKind::None,
             &target_dir,
-            cg_clif_build_dir,
+            cg_clif_dylib,
             &host_triple,
             &target_triple,
         );
@@ -427,7 +422,7 @@ pub(crate) fn run_tests(
             channel,
             sysroot_kind,
             &target_dir,
-            cg_clif_build_dir,
+            cg_clif_dylib,
             &host_triple,
             &target_triple,
         );
@@ -521,16 +516,8 @@ impl TestRunner {
         }
     }
 
-    fn in_dir<'a, I, F>(&self, dir: I, callback: F)
-    where
-        I: IntoIterator<Item = &'a str>,
-        F: FnOnce(&TestRunner),
-    {
+    fn in_dir(&self, new: impl AsRef<Path>, callback: impl FnOnce(&TestRunner)) {
         let current = env::current_dir().unwrap();
-        let mut new = current.clone();
-        for d in dir {
-            new.push(d);
-        }
 
         env::set_current_dir(new).unwrap();
         callback(self);
@@ -595,25 +582,29 @@ impl TestRunner {
         spawn_and_wait(cmd);
     }
 
-    fn cargo_command<I, S>(&self, args: I) -> Command
+    fn cargo_command<'a, I>(&self, subcommand: &str, args: I) -> Command
     where
-        I: IntoIterator<Item = S>,
-        S: AsRef<OsStr>,
+        I: IntoIterator<Item = &'a str>,
     {
         let mut cargo_clif = self.root_dir.clone();
         cargo_clif.push("build");
         cargo_clif.push(get_wrapper_file_name("cargo-clif", "bin"));
 
-        let mut cmd = Command::new(cargo_clif);
+        let mut cmd = cargo_command(
+            cargo_clif,
+            subcommand,
+            if subcommand == "clean" { None } else { Some(&self.target_triple) },
+            Path::new("."),
+        );
         cmd.args(args);
         cmd.env("RUSTFLAGS", &self.rust_flags);
         cmd
     }
 
-    fn run_cargo<'a, I>(&self, args: I)
+    fn run_cargo<'a, I>(&self, subcommand: &str, args: I)
     where
         I: IntoIterator<Item = &'a str>,
     {
-        spawn_and_wait(self.cargo_command(args));
+        spawn_and_wait(self.cargo_command(subcommand, args));
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs
index bdf8f8ecd99..48da64906e2 100644
--- a/compiler/rustc_codegen_cranelift/build_system/utils.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs
@@ -4,6 +4,52 @@ use std::io::Write;
 use std::path::Path;
 use std::process::{self, Command, Stdio};
 
+pub(crate) fn cargo_command(
+    cargo: impl AsRef<Path>,
+    subcommand: &str,
+    triple: Option<&str>,
+    source_dir: &Path,
+) -> Command {
+    let mut cmd = Command::new(cargo.as_ref());
+    cmd.arg(subcommand)
+        .arg("--manifest-path")
+        .arg(source_dir.join("Cargo.toml"))
+        .arg("--target-dir")
+        .arg(source_dir.join("target"));
+
+    if let Some(triple) = triple {
+        cmd.arg("--target").arg(triple);
+    }
+
+    cmd
+}
+
+pub(crate) fn hyperfine_command(
+    warmup: u64,
+    runs: u64,
+    prepare: Option<Command>,
+    a: Command,
+    b: Command,
+) -> Command {
+    let mut bench = Command::new("hyperfine");
+
+    if warmup != 0 {
+        bench.arg("--warmup").arg(warmup.to_string());
+    }
+
+    if runs != 0 {
+        bench.arg("--runs").arg(runs.to_string());
+    }
+
+    if let Some(prepare) = prepare {
+        bench.arg("--prepare").arg(format!("{:?}", prepare));
+    }
+
+    bench.arg(format!("{:?}", a)).arg(format!("{:?}", b));
+
+    bench
+}
+
 #[track_caller]
 pub(crate) fn try_hard_link(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
     let src = src.as_ref();
diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh
index 62e52bd1958..fedab2433aa 100755
--- a/compiler/rustc_codegen_cranelift/clean_all.sh
+++ b/compiler/rustc_codegen_cranelift/clean_all.sh
@@ -3,4 +3,8 @@ set -e
 
 rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
 rm -rf target/ build/ perf.data{,.old} y.bin
-rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/
+rm -rf download/
+
+# Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh
+# FIXME remove at some point in the future
+rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ abi-cafe/
diff --git a/compiler/rustc_codegen_cranelift/config.txt b/compiler/rustc_codegen_cranelift/config.txt
index 2264d301d59..0d539191b12 100644
--- a/compiler/rustc_codegen_cranelift/config.txt
+++ b/compiler/rustc_codegen_cranelift/config.txt
@@ -49,4 +49,4 @@ test.regex-shootout-regex-dna
 test.regex
 test.portable-simd
 
-testsuite.abi-checker
+testsuite.abi-cafe
diff --git a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
index 2ecc8b8238b..03910069633 100644
--- a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
+++ b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
@@ -5,7 +5,6 @@
 // Test that we can handle unsized types with an extern type tail part.
 // Regression test for issue #91827.
 
-#![feature(const_ptr_offset_from)]
 #![feature(extern_types)]
 
 use std::ptr::addr_of;
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 42f8aa50ba1..7f85b52f083 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -559,16 +559,22 @@ pub union MaybeUninit<T> {
 
 pub mod intrinsics {
     extern "rust-intrinsic" {
+        #[rustc_safe_intrinsic]
         pub fn abort() -> !;
+        #[rustc_safe_intrinsic]
         pub fn size_of<T>() -> usize;
         pub fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
+        #[rustc_safe_intrinsic]
         pub fn min_align_of<T>() -> usize;
         pub fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
         pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
         pub fn transmute<T, U>(e: T) -> U;
         pub fn ctlz_nonzero<T>(x: T) -> T;
+        #[rustc_safe_intrinsic]
         pub fn needs_drop<T: ?::Sized>() -> bool;
+        #[rustc_safe_intrinsic]
         pub fn bitreverse<T>(x: T) -> T;
+        #[rustc_safe_intrinsic]
         pub fn bswap<T>(x: T) -> T;
         pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
     }
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 e83be3a3df5..215d3556a17 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -93,6 +93,7 @@ fn start<T: Termination + 'static>(
     main: fn() -> T,
     argc: isize,
     argv: *const *const u8,
+    _sigpipe: u8,
 ) -> isize {
     if argc == 3 {
         unsafe { puts(*argv as *const i8); }
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch b/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch
new file mode 100644
index 00000000000..0e5e7cdfcdf
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch
@@ -0,0 +1,29 @@
+From 2b15fee2bb5fd14e34c7e17e44d99cb34f4c555d Mon Sep 17 00:00:00 2001
+From: Afonso Bordado <afonsobordado@az8.co>
+Date: Tue, 27 Sep 2022 07:55:17 +0100
+Subject: [PATCH] Disable some test on x86_64-pc-windows-gnu
+
+---
+ src/report.rs | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/src/report.rs b/src/report.rs
+index eeec614..f582867 100644
+--- a/src/report.rs
++++ b/src/report.rs
+@@ -48,6 +48,12 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl
+     //
+     // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
+ 
++    // x86_64-pc-windows-gnu has some broken i128 tests that aren't disabled by default
++    if cfg!(all(target_os = "windows", target_env = "gnu")) && test.test_name == "ui128" {
++        result.run = Link;
++        result.check = Pass(Link);
++    }
++
+     // END OF VENDOR RESERVED AREA
+     //
+     //
+-- 
+2.30.1.windows.1
+
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch
deleted file mode 100644
index 526366a7598..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 1a315ba225577dbbd1f449d9609f16f984f68708 Mon Sep 17 00:00:00 2001
-From: Afonso Bordado <afonso360@users.noreply.github.com>
-Date: Fri, 12 Aug 2022 22:51:58 +0000
-Subject: [PATCH] Disable abi-checker tests
-
----
- src/report.rs | 14 ++++++++++++++
- 1 file changed, 14 insertions(+)
-
-diff --git a/src/report.rs b/src/report.rs
-index 7346f5e..8347762 100644
---- a/src/report.rs
-+++ b/src/report.rs
-@@ -45,6 +45,20 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl
-     //
-     // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
-
-+    // Currently MSVC has some broken ABI issues. Furthermore, they cause
-+    // a STATUS_ACCESS_VIOLATION, so we can't even run them. Ensure that they compile and link.
-+    if cfg!(windows) && (test.test_name == "bool" || test.test_name == "ui128") {
-+        result.run = Link;
-+        result.check = Pass(Link);
-+    }
-+
-+    // structs is broken in the current release of cranelift for aarch64.
-+    // It has been fixed for cranelift 0.88: https://github.com/bytecodealliance/wasmtime/pull/4634
-+    if cfg!(target_arch = "aarch64") && test.test_name == "structs" {
-+        result.run = Link;
-+        result.check = Pass(Link);
-+    }
-+
-     // END OF VENDOR RESERVED AREA
-     //
-     //
---
-2.34.1
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
index 54e13b090ab..89e2b61c1fc 100644
--- a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
@@ -1,80 +1,29 @@
-From 97c473937382a5b5858d9cce3c947855d23b2dc5 Mon Sep 17 00:00:00 2001
+From b742f03694b920cc14400727d54424e8e1b60928 Mon Sep 17 00:00:00 2001
 From: bjorn3 <bjorn3@users.noreply.github.com>
 Date: Thu, 18 Nov 2021 19:28:40 +0100
 Subject: [PATCH] Disable unsupported tests
 
 ---
- crates/core_simd/src/math.rs         | 6 ++++++
- crates/core_simd/src/vector.rs       | 2 ++
- crates/core_simd/tests/masks.rs      | 2 ++
- crates/core_simd/tests/ops_macros.rs | 4 ++++
- 4 files changed, 14 insertions(+)
+ crates/core_simd/src/elements/int.rs     | 8 ++++++++
+ crates/core_simd/src/elements/uint.rs    | 4 ++++
+ crates/core_simd/src/masks/full_masks.rs | 6 ++++++
+ crates/core_simd/src/vector.rs           | 2 ++
+ crates/core_simd/tests/masks.rs          | 3 ---
+ 5 files changed, 20 insertions(+), 3 deletions(-)
 
-diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs
-index 2bae414..2f87499 100644
---- a/crates/core_simd/src/math.rs
-+++ b/crates/core_simd/src/math.rs
-@@ -5,6 +5,7 @@ macro_rules! impl_uint_arith {
-     ($($ty:ty),+) => {
-         $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
- 
-+            /*
-             /// Lanewise saturating add.
-             ///
-             /// # Examples
-@@ -43,6 +44,7 @@ macro_rules! impl_uint_arith {
-             pub fn saturating_sub(self, second: Self) -> Self {
-                 unsafe { simd_saturating_sub(self, second) }
-             }
-+            */
-         })+
-     }
- }
-@@ -51,6 +53,7 @@ macro_rules! impl_int_arith {
-     ($($ty:ty),+) => {
-         $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
- 
-+            /*
-             /// Lanewise saturating add.
-             ///
-             /// # Examples
-@@ -89,6 +92,7 @@ macro_rules! impl_int_arith {
-             pub fn saturating_sub(self, second: Self) -> Self {
-                 unsafe { simd_saturating_sub(self, second) }
-             }
-+            */
- 
-             /// Lanewise absolute value, implemented in Rust.
-             /// Every lane becomes its absolute value.
-@@ -109,6 +113,7 @@ macro_rules! impl_int_arith {
-                 (self^m) - m
-             }
- 
-+            /*
-             /// Lanewise saturating absolute value, implemented in Rust.
-             /// As abs(), except the MIN value becomes MAX instead of itself.
-             ///
-@@ -151,6 +156,7 @@ macro_rules! impl_int_arith {
-             pub fn saturating_neg(self) -> Self {
-                 Self::splat(0).saturating_sub(self)
-             }
-+            */
-         })+
-     }
- }
 diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs
-index 7c5ec2b..c8631e8 100644
+index e8e8f68..7173c24 100644
 --- a/crates/core_simd/src/vector.rs
 +++ b/crates/core_simd/src/vector.rs
-@@ -75,6 +75,7 @@ where
-         Self(array)
+@@ -250,6 +250,7 @@ where
+         unsafe { intrinsics::simd_cast(self) }
      }
  
 +    /*
      /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
      /// If an index is out-of-bounds, the lane is instead selected from the `or` vector.
      ///
-@@ -297,6 +298,7 @@ where
+@@ -473,6 +474,7 @@ where
              // Cleared ☢️ *mut T Zone
          }
      }
@@ -82,26 +31,5 @@ index 7c5ec2b..c8631e8 100644
  }
  
  impl<T, const LANES: usize> Copy for Simd<T, LANES>
-diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs
-index 6a8ecd3..68fcb49 100644
---- a/crates/core_simd/tests/masks.rs
-+++ b/crates/core_simd/tests/masks.rs
-@@ -68,6 +68,7 @@ macro_rules! test_mask_api {
-                 assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask);
-             }
- 
-+            /*
-             #[cfg(feature = "generic_const_exprs")]
-             #[test]
-             fn roundtrip_bitmask_conversion() {
-@@ -80,6 +81,7 @@ macro_rules! test_mask_api {
-                 assert_eq!(bitmask, [0b01001001, 0b10000011]);
-                 assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask);
-             }
-+            */
-         }
-     }
- }
 -- 
-2.26.2.7.g19db9cfb68
-
+2.25.1
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
new file mode 100644
index 00000000000..d8775e2d022
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch
@@ -0,0 +1,47 @@
+From eec874c889b8d24e5ad50faded24288150f057b1 Mon Sep 17 00:00:00 2001
+From: Afonso Bordado <afonsobordado@az8.co>
+Date: Tue, 27 Sep 2022 08:13:58 +0100
+Subject: [PATCH] Disable rand tests on mingw
+
+---
+ rand_distr/src/pareto.rs            | 2 ++
+ rand_distr/tests/value_stability.rs | 4 ++++
+ 2 files changed, 6 insertions(+)
+
+diff --git a/rand_distr/src/pareto.rs b/rand_distr/src/pareto.rs
+index 217899e..9cedeb7 100644
+--- a/rand_distr/src/pareto.rs
++++ b/rand_distr/src/pareto.rs
+@@ -107,6 +107,8 @@ mod tests {
+     }
+
+     #[test]
++    // 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],
+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
++++ b/rand_distr/tests/value_stability.rs
+@@ -72,6 +72,8 @@ fn unit_disc_stability() {
+ }
+
+ #[test]
++// This is broken on x86_64-pc-windows-gnu
++#[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)]
+ fn pareto_stability() {
+     test_samples(213, Pareto::new(1.0, 1.0).unwrap(), &[
+         1.0423688f32, 2.1235929, 4.132709, 1.4679428,
+@@ -143,6 +145,8 @@ fn inverse_gaussian_stability() {
+ }
+
+ #[test]
++// This is broken on x86_64-pc-windows-gnu
++#[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)]
+ fn gamma_stability() {
+     // Gamma has 3 cases: shape == 1, shape < 1, shape > 1
+     test_samples(223, Gamma::new(1.0, 5.0).unwrap(), &[
+--
+2.25.1
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 14f2746ecb1..c0a2e7a7883 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-08-24"
+channel = "nightly-2022-10-23"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
index 091bfa1e992..d6a37789599 100644
--- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
@@ -10,6 +10,8 @@ git fetch
 git checkout -- .
 git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')"
 
+git am ../patches/*-sysroot-*.patch
+
 git apply - <<EOF
 diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
 index d95b5b7f17f..00b6f0e3635 100644
@@ -66,3 +68,7 @@ popd
 
 # FIXME remove once inline asm is fully supported
 export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc"
+
+# Allow the testsuite to use llvm tools
+host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
+export LLVM_BIN_DIR="$(rustc --print sysroot)/lib/rustlib/$host_triple/bin"
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index 944787612d8..9b5db3cf81f 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -29,10 +29,6 @@ rm src/test/incremental/change_crate_dep_kind.rs
 rm src/test/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort instead of exit(101)
 
 # requires compiling with -Cpanic=unwind
-rm src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs # "Cannot run dynamic test fn out-of-process"
-rm src/test/ui/async-await/async-fn-size-moved-locals.rs # -Cpanic=abort shrinks some generator by one byte
-rm src/test/ui/async-await/async-fn-size-uninit-locals.rs # same
-rm src/test/ui/generator/size-moved-locals.rs # same
 rm -r src/test/ui/macros/rfc-2011-nicer-assert-messages/
 
 # vendor intrinsics
@@ -67,6 +63,7 @@ rm src/test/ui/target-feature/missing-plusminus.rs # error not implemented
 rm src/test/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
 rm -r src/test/run-make/emit-named-files # requires full --emit support
 rm src/test/ui/abi/stack-probes.rs # stack probes not yet implemented
+rm src/test/ui/simd/intrinsic/ptr-cast.rs # simd_expose_addr intrinsic unimplemented
 
 # optimization tests
 # ==================
@@ -110,12 +107,13 @@ rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unorde
 # bugs in the test suite
 # ======================
 rm src/test/ui/backtrace.rs # TODO warning
-rm src/test/ui/empty_global_asm.rs # TODO add needs-asm-support
 rm src/test/ui/simple_global_asm.rs # TODO add needs-asm-support
 rm src/test/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout
 # not sure if this is actually a bug in the test suite, but the symbol list shows the function without leading _ for some reason
 rm -r src/test/run-make/native-link-modifier-bundle
 
+rm src/test/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
+
 echo "[TEST] rustc test suite"
 RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
 popd
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 0497c2570e6..99059e788a0 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -465,7 +465,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
             let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
             let sig = fx.bcx.import_signature(sig);
 
-            (CallTarget::Indirect(sig, method), Some(ptr))
+            (CallTarget::Indirect(sig, method), Some(ptr.get_addr(fx)))
         }
 
         // Normal call
@@ -560,7 +560,19 @@ pub(crate) fn codegen_drop<'tcx>(
         // we don't actually need to drop anything
     } else {
         match ty.kind() {
-            ty::Dynamic(..) => {
+            ty::Dynamic(_, _, ty::Dyn) => {
+                // IN THIS ARM, WE HAVE:
+                // ty = *mut (dyn Trait)
+                // which is: exists<T> ( *mut T,    Vtable<T: Trait> )
+                //                       args[0]    args[1]
+                //
+                // args = ( Data, Vtable )
+                //                  |
+                //                  v
+                //                /-------\
+                //                | ...   |
+                //                \-------/
+                //
                 let (ptr, vtable) = drop_place.to_ptr_maybe_unsized();
                 let ptr = ptr.get_addr(fx);
                 let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable.unwrap());
@@ -578,6 +590,43 @@ pub(crate) fn codegen_drop<'tcx>(
                 let sig = fx.bcx.import_signature(sig);
                 fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]);
             }
+            ty::Dynamic(_, _, ty::DynStar) => {
+                // IN THIS ARM, WE HAVE:
+                // ty = *mut (dyn* Trait)
+                // which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
+                //
+                // args = [ * ]
+                //          |
+                //          v
+                //      ( Data, Vtable )
+                //                |
+                //                v
+                //              /-------\
+                //              | ...   |
+                //              \-------/
+                //
+                //
+                // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
+                //
+                // data = &(*args[0]).0    // gives a pointer to Data above (really the same pointer)
+                // vtable = (*args[0]).1   // loads the vtable out
+                // (data, vtable)          // an equivalent Rust `*mut dyn Trait`
+                //
+                // SO THEN WE CAN USE THE ABOVE CODE.
+                let (data, vtable) = drop_place.to_cvalue(fx).dyn_star_force_data_on_stack(fx);
+                let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable);
+
+                let virtual_drop = Instance {
+                    def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
+                    substs: drop_instance.substs,
+                };
+                let fn_abi =
+                    RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
+
+                let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
+                let sig = fx.bcx.import_signature(sig);
+                fx.bcx.ins().call_indirect(sig, drop_fn, &[data]);
+            }
             _ => {
                 assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
 
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index 96e25d3a8d4..e5ad31eb948 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -193,7 +193,7 @@ pub(super) fn from_casted_value<'tcx>(
         kind: StackSlotKind::ExplicitSlot,
         // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
         // specify stack slot alignment.
-        // Stack slot size may be bigger for for example `[u8; 3]` which is packed into an `i32`.
+        // Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
         // It may also be smaller for example when the type is a wrapper around an integer with a
         // larger alignment than the integer.
         size: (std::cmp::max(abi_param_size, layout_size) + 15) / 16 * 16,
diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs
index 6d321c7b298..12bb00d346d 100644
--- a/compiler/rustc_codegen_cranelift/src/allocator.rs
+++ b/compiler/rustc_codegen_cranelift/src/allocator.rs
@@ -5,6 +5,7 @@ use crate::prelude::*;
 
 use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
 use rustc_session::config::OomStrategy;
+use rustc_span::symbol::sym;
 
 /// Returns whether an allocator shim was created
 pub(crate) fn codegen(
@@ -23,7 +24,7 @@ pub(crate) fn codegen(
             module,
             unwind_context,
             kind,
-            tcx.lang_items().oom().is_some(),
+            tcx.alloc_error_handler_kind(()).unwrap(),
             tcx.sess.opts.unstable_opts.oom,
         );
         true
@@ -36,7 +37,7 @@ fn codegen_inner(
     module: &mut impl Module,
     unwind_context: &mut UnwindContext,
     kind: AllocatorKind,
-    has_alloc_error_handler: bool,
+    alloc_error_handler_kind: AllocatorKind,
     oom_strategy: OomStrategy,
 ) {
     let usize_ty = module.target_config().pointer_type();
@@ -78,7 +79,7 @@ fn codegen_inner(
         let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();
 
         let mut ctx = Context::new();
-        ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig.clone());
+        ctx.func.signature = sig.clone();
         {
             let mut func_ctx = FunctionBuilderContext::new();
             let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
@@ -108,15 +109,15 @@ fn codegen_inner(
         returns: vec![],
     };
 
-    let callee_name = if has_alloc_error_handler { "__rg_oom" } else { "__rdl_oom" };
+    let callee_name = alloc_error_handler_kind.fn_name(sym::oom);
 
     let func_id =
         module.declare_function("__rust_alloc_error_handler", Linkage::Export, &sig).unwrap();
 
-    let callee_func_id = module.declare_function(callee_name, Linkage::Import, &sig).unwrap();
+    let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();
 
     let mut ctx = Context::new();
-    ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig);
+    ctx.func.signature = sig;
     {
         let mut func_ctx = FunctionBuilderContext::new();
         let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
index b4c79096170..f2e3bf16e61 100644
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ b/compiler/rustc_codegen_cranelift/src/archive.rs
@@ -38,6 +38,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
         _lib_name: &str,
         _dll_imports: &[rustc_session::cstore::DllImport],
         _tmpdir: &Path,
+        _is_direct_dependency: bool,
     ) -> PathBuf {
         bug!("creating dll imports is not supported");
     }
@@ -159,6 +160,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
                         let err = err.to_string();
                         if err == "Unknown file magic" {
                             // Not an object file; skip it.
+                        } else if object::read::archive::ArchiveFile::parse(&*data).is_ok() {
+                            // Nested archive file; skip it.
                         } else {
                             sess.fatal(&format!(
                                 "error parsing `{}` during archive creation: {}",
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 4303d63fe21..1db44502742 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -6,6 +6,8 @@ use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 
+use cranelift_codegen::ir::UserFuncName;
+
 use crate::constant::ConstantCx;
 use crate::debuginfo::FunctionDebugContext;
 use crate::prelude::*;
@@ -64,7 +66,7 @@ pub(crate) fn codegen_fn<'tcx>(
     let mut func_ctx = FunctionBuilderContext::new();
     let mut func = cached_func;
     func.clear();
-    func.name = ExternalName::user(0, func_id.as_u32());
+    func.name = UserFuncName::user(0, func_id.as_u32());
     func.signature = sig;
     func.collect_debug_info();
 
@@ -706,9 +708,9 @@ fn codegen_stmt<'tcx>(
                     let operand = codegen_operand(fx, operand);
                     operand.unsize_value(fx, lval);
                 }
-                Rvalue::Cast(CastKind::DynStar, _, _) => {
-                    // FIXME(dyn-star)
-                    unimplemented!()
+                Rvalue::Cast(CastKind::DynStar, ref operand, _) => {
+                    let operand = codegen_operand(fx, operand);
+                    operand.coerce_dyn_star(fx, lval);
                 }
                 Rvalue::Discriminant(place) => {
                     let place = codegen_place(fx, place);
@@ -768,11 +770,7 @@ fn codegen_stmt<'tcx>(
                     lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
                 }
                 Rvalue::NullaryOp(null_op, ty) => {
-                    assert!(
-                        lval.layout()
-                            .ty
-                            .is_sized(fx.tcx.at(stmt.source_info.span), ParamEnv::reveal_all())
-                    );
+                    assert!(lval.layout().ty.is_sized(fx.tcx, ParamEnv::reveal_all()));
                     let layout = fx.layout_of(fx.monomorphize(ty));
                     let val = match null_op {
                         NullOp::SizeOf => layout.size.bytes(),
@@ -922,7 +920,7 @@ pub(crate) fn codegen_operand<'tcx>(
             let cplace = codegen_place(fx, *place);
             cplace.to_cvalue(fx)
         }
-        Operand::Constant(const_) => crate::constant::codegen_constant(fx, const_),
+        Operand::Constant(const_) => crate::constant::codegen_constant_operand(fx, const_),
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
index dfde9792046..f855e20e0a1 100644
--- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
+++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
@@ -10,6 +10,7 @@ pub(super) struct ConcurrencyLimiter {
     helper_thread: Option<HelperThread>,
     state: Arc<Mutex<state::ConcurrencyLimiterState>>,
     available_token_condvar: Arc<Condvar>,
+    finished: bool,
 }
 
 impl ConcurrencyLimiter {
@@ -32,6 +33,7 @@ impl ConcurrencyLimiter {
             helper_thread: Some(helper_thread),
             state,
             available_token_condvar: Arc::new(Condvar::new()),
+            finished: false,
         }
     }
 
@@ -56,16 +58,23 @@ impl ConcurrencyLimiter {
         let mut state = self.state.lock().unwrap();
         state.job_already_done();
     }
-}
 
-impl Drop for ConcurrencyLimiter {
-    fn drop(&mut self) {
-        //
+    pub(crate) fn finished(mut self) {
         self.helper_thread.take();
 
         // Assert that all jobs have finished
         let state = Mutex::get_mut(Arc::get_mut(&mut self.state).unwrap()).unwrap();
         state.assert_done();
+
+        self.finished = true;
+    }
+}
+
+impl Drop for ConcurrencyLimiter {
+    fn drop(&mut self) {
+        if !self.finished && !std::thread::panicking() {
+            panic!("Forgot to call finished() on ConcurrencyLimiter");
+        }
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index c5f44bb8479..148b66d959e 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -5,9 +5,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{
     read_target_uint, AllocId, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
 };
-use rustc_span::DUMMY_SP;
 
-use cranelift_codegen::ir::GlobalValueData;
 use cranelift_module::*;
 
 use crate::prelude::*;
@@ -81,53 +79,46 @@ pub(crate) fn codegen_tls_ref<'tcx>(
     CValue::by_val(tls_ptr, layout)
 }
 
-fn codegen_static_ref<'tcx>(
-    fx: &mut FunctionCx<'_, '_, 'tcx>,
-    def_id: DefId,
-    layout: TyAndLayout<'tcx>,
-) -> CPlace<'tcx> {
-    let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
-    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
-    if fx.clif_comments.enabled() {
-        fx.add_comment(local_data_id, format!("{:?}", def_id));
-    }
-    let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
-    assert!(!layout.is_unsized(), "unsized statics aren't supported");
-    assert!(
-        matches!(
-            fx.bcx.func.global_values[local_data_id],
-            GlobalValueData::Symbol { tls: false, .. }
-        ),
-        "tls static referenced without Rvalue::ThreadLocalRef"
-    );
-    CPlace::for_ptr(crate::pointer::Pointer::new(global_ptr), layout)
-}
-
-pub(crate) fn codegen_constant<'tcx>(
+pub(crate) fn eval_mir_constant<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     constant: &Constant<'tcx>,
-) -> CValue<'tcx> {
-    let (const_val, ty) = match fx.monomorphize(constant.literal) {
-        ConstantKind::Ty(const_) => unreachable!("{:?}", const_),
-        ConstantKind::Unevaluated(mir::UnevaluatedConst { def, substs, promoted }, ty)
+) -> (ConstValue<'tcx>, Ty<'tcx>) {
+    let constant_kind = fx.monomorphize(constant.literal);
+    let uv = match constant_kind {
+        ConstantKind::Ty(const_) => match const_.kind() {
+            ty::ConstKind::Unevaluated(uv) => uv.expand(),
+            ty::ConstKind::Value(val) => {
+                return (fx.tcx.valtree_to_const_val((const_.ty(), val)), const_.ty());
+            }
+            err => span_bug!(
+                constant.span,
+                "encountered bad ConstKind after monomorphizing: {:?}",
+                err
+            ),
+        },
+        ConstantKind::Unevaluated(mir::UnevaluatedConst { def, .. }, _)
             if fx.tcx.is_static(def.did) =>
         {
-            assert!(substs.is_empty());
-            assert!(promoted.is_none());
-
-            return codegen_static_ref(fx, def.did, fx.layout_of(ty)).to_cvalue(fx);
-        }
-        ConstantKind::Unevaluated(unevaluated, ty) => {
-            match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) {
-                Ok(const_val) => (const_val, ty),
-                Err(_) => {
-                    span_bug!(constant.span, "erroneous constant not captured by required_consts");
-                }
-            }
+            span_bug!(constant.span, "MIR constant refers to static");
         }
-        ConstantKind::Val(val, ty) => (val, ty),
+        ConstantKind::Unevaluated(uv, _) => uv,
+        ConstantKind::Val(val, _) => return (val, constant_kind.ty()),
     };
 
+    (
+        fx.tcx.const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).unwrap_or_else(|_err| {
+            span_bug!(constant.span, "erroneous constant not captured by required_consts");
+        }),
+        constant_kind.ty(),
+    )
+}
+
+pub(crate) fn codegen_constant_operand<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    constant: &Constant<'tcx>,
+) -> CValue<'tcx> {
+    let (const_val, ty) = eval_mir_constant(fx, constant);
+
     codegen_const_value(fx, const_val, ty)
 }
 
@@ -244,7 +235,7 @@ pub(crate) fn codegen_const_value<'tcx>(
     }
 }
 
-pub(crate) fn pointer_for_allocation<'tcx>(
+fn pointer_for_allocation<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     alloc: ConstAllocation<'tcx>,
 ) -> crate::pointer::Pointer {
@@ -299,7 +290,7 @@ fn data_id_for_static(
     let is_mutable = if tcx.is_mutable_static(def_id) {
         true
     } else {
-        !ty.is_freeze(tcx.at(DUMMY_SP), ParamEnv::reveal_all())
+        !ty.is_freeze(tcx, ParamEnv::reveal_all())
     };
     let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
 
@@ -467,14 +458,13 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
     operand: &Operand<'tcx>,
 ) -> Option<ConstValue<'tcx>> {
     match operand {
-        Operand::Constant(const_) => match const_.literal {
-            ConstantKind::Ty(const_) => fx
-                .monomorphize(const_)
-                .eval_for_mir(fx.tcx, ParamEnv::reveal_all())
-                .try_to_value(fx.tcx),
+        Operand::Constant(const_) => match fx.monomorphize(const_.literal) {
+            ConstantKind::Ty(const_) => Some(
+                const_.eval_for_mir(fx.tcx, ParamEnv::reveal_all()).try_to_value(fx.tcx).unwrap(),
+            ),
             ConstantKind::Val(val, _) => Some(val),
             ConstantKind::Unevaluated(uv, _) => {
-                fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), uv, None).ok()
+                Some(fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), uv, None).unwrap())
             }
         },
         // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 8eabe1cbcb1..f873561c171 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -106,7 +106,7 @@ impl OngoingCodegen {
             }
         }
 
-        drop(self.concurrency_limiter);
+        self.concurrency_limiter.finished();
 
         (
             CodegenResults {
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index 0e77e4004c0..6a430b5215e 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -67,13 +67,12 @@ fn create_jit_module(
     hotswap: bool,
 ) -> (JITModule, CodegenCx) {
     let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string());
-    let imported_symbols = load_imported_symbols_for_jit(tcx.sess, crate_info);
 
     let isa = crate::build_isa(tcx.sess, backend_config);
     let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
     jit_builder.hotswap(hotswap);
     crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
-    jit_builder.symbols(imported_symbols);
+    jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info));
     jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8);
     let mut jit_module = JITModule::new(jit_builder);
 
@@ -286,10 +285,10 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
     })
 }
 
-fn load_imported_symbols_for_jit(
+fn dep_symbol_lookup_fn(
     sess: &Session,
     crate_info: CrateInfo,
-) -> Vec<(String, *const u8)> {
+) -> Box<dyn Fn(&str) -> Option<*const u8>> {
     use rustc_middle::middle::dependency_format::Linkage;
 
     let mut dylib_paths = Vec::new();
@@ -316,39 +315,23 @@ fn load_imported_symbols_for_jit(
         }
     }
 
-    let mut imported_symbols = Vec::new();
-    for path in dylib_paths {
-        use object::{Object, ObjectSymbol};
-        let lib = libloading::Library::new(&path).unwrap();
-        let obj = std::fs::read(path).unwrap();
-        let obj = object::File::parse(&*obj).unwrap();
-        imported_symbols.extend(obj.dynamic_symbols().filter_map(|symbol| {
-            let name = symbol.name().unwrap().to_string();
-            if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
-                return None;
-            }
-            if name.starts_with("rust_metadata_") {
-                // The metadata is part of a section that is not loaded by the dynamic linker in
-                // case of cg_llvm.
-                return None;
-            }
-            let dlsym_name = if cfg!(target_os = "macos") {
-                // On macOS `dlsym` expects the name without leading `_`.
-                assert!(name.starts_with('_'), "{:?}", name);
-                &name[1..]
-            } else {
-                &name
-            };
-            let symbol: libloading::Symbol<'_, *const u8> =
-                unsafe { lib.get(dlsym_name.as_bytes()) }.unwrap();
-            Some((name, *symbol))
-        }));
-        std::mem::forget(lib)
-    }
+    let imported_dylibs = Box::leak(
+        dylib_paths
+            .into_iter()
+            .map(|path| unsafe { libloading::Library::new(&path).unwrap() })
+            .collect::<Box<[_]>>(),
+    );
 
     sess.abort_if_errors();
 
-    imported_symbols
+    Box::new(move |sym_name| {
+        for dylib in &*imported_dylibs {
+            if let Ok(sym) = unsafe { dylib.get::<*const u8>(sym_name.as_bytes()) } {
+                return Some(*sym);
+            }
+        }
+        None
+    })
 }
 
 fn codegen_shim<'tcx>(
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 8b3d475cb18..3fcc84d3929 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -27,7 +27,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
         }
 
         // Used by stdarch
-        if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
+        if template[0] == InlineAsmTemplatePiece::String("mov ".to_string())
             && matches!(
                 template[1],
                 InlineAsmTemplatePiece::Placeholder {
@@ -36,24 +36,26 @@ pub(crate) fn codegen_inline_asm<'tcx>(
                     span: _
                 }
             )
-            && template[2] == InlineAsmTemplatePiece::String("\n".to_string())
-            && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string())
-            && template[4] == InlineAsmTemplatePiece::String("\n".to_string())
-            && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string())
+            && template[2] == InlineAsmTemplatePiece::String(", rbx".to_string())
+            && template[3] == InlineAsmTemplatePiece::String("\n".to_string())
+            && template[4] == InlineAsmTemplatePiece::String("cpuid".to_string())
+            && template[5] == InlineAsmTemplatePiece::String("\n".to_string())
+            && template[6] == InlineAsmTemplatePiece::String("xchg ".to_string())
             && matches!(
-                template[6],
+                template[7],
                 InlineAsmTemplatePiece::Placeholder {
                     operand_idx: 0,
                     modifier: Some('r'),
                     span: _
                 }
             )
+            && template[8] == InlineAsmTemplatePiece::String(", rbx".to_string())
         {
             assert_eq!(operands.len(), 4);
             let (leaf, eax_place) = match operands[1] {
                 InlineAsmOperand::InOut {
                     reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
-                    late: true,
+                    late: _,
                     ref in_value,
                     out_place: Some(out_place),
                 } => (
@@ -68,7 +70,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
                         InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
                             X86InlineAsmRegClass::reg,
                         )),
-                    late: true,
+                    late: _,
                     place: Some(place),
                 } => crate::base::codegen_place(fx, place),
                 _ => unreachable!(),
@@ -76,7 +78,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
             let (sub_leaf, ecx_place) = match operands[2] {
                 InlineAsmOperand::InOut {
                     reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)),
-                    late: true,
+                    late: _,
                     ref in_value,
                     out_place: Some(out_place),
                 } => (
@@ -88,7 +90,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
             let edx_place = match operands[3] {
                 InlineAsmOperand::Out {
                     reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
-                    late: true,
+                    late: _,
                     place: Some(place),
                 } => crate::base::codegen_place(fx, place),
                 _ => unreachable!(),
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
index a799dca938e..783d426c30b 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
@@ -14,6 +14,10 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
     target: Option<BasicBlock>,
 ) {
     match intrinsic {
+        "llvm.x86.sse2.pause" | "llvm.aarch64.isb" => {
+            // Spin loop hint
+        }
+
         // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
         "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => {
             intrinsic_args!(fx, args => (a); intrinsic);
@@ -25,8 +29,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
             let mut res = fx.bcx.ins().iconst(types::I32, 0);
 
             for lane in (0..lane_count).rev() {
-                let a_lane =
-                    a.value_field(fx, mir::Field::new(lane.try_into().unwrap())).load_scalar(fx);
+                let a_lane = a.value_lane(fx, lane).load_scalar(fx);
 
                 // cast float to int
                 let a_lane = match lane_ty {
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 2e4ca594f91..0302b843aa2 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -84,6 +84,30 @@ fn simd_for_each_lane<'tcx>(
     }
 }
 
+fn simd_pair_for_each_lane_typed<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    x: CValue<'tcx>,
+    y: CValue<'tcx>,
+    ret: CPlace<'tcx>,
+    f: &dyn Fn(&mut FunctionCx<'_, '_, 'tcx>, CValue<'tcx>, CValue<'tcx>) -> CValue<'tcx>,
+) {
+    assert_eq!(x.layout(), y.layout());
+    let layout = x.layout();
+
+    let (lane_count, _lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+    let (ret_lane_count, _ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+    assert_eq!(lane_count, ret_lane_count);
+
+    for lane_idx in 0..lane_count {
+        let x_lane = x.value_lane(fx, lane_idx);
+        let y_lane = y.value_lane(fx, lane_idx);
+
+        let res_lane = f(fx, x_lane, y_lane);
+
+        ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
+    }
+}
+
 fn simd_pair_for_each_lane<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     x: CValue<'tcx>,
@@ -504,37 +528,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 _ => unreachable!(),
             };
 
-            let signed = type_sign(lhs.layout().ty);
-
-            let checked_res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs);
-
-            let (val, has_overflow) = checked_res.load_scalar_pair(fx);
-            let clif_ty = fx.clif_type(lhs.layout().ty).unwrap();
-
-            let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed);
-
-            let val = match (intrinsic, signed) {
-                (sym::saturating_add, false) => fx.bcx.ins().select(has_overflow, max, val),
-                (sym::saturating_sub, false) => fx.bcx.ins().select(has_overflow, min, val),
-                (sym::saturating_add, true) => {
-                    let rhs = rhs.load_scalar(fx);
-                    let rhs_ge_zero =
-                        fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
-                    let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
-                    fx.bcx.ins().select(has_overflow, sat_val, val)
-                }
-                (sym::saturating_sub, true) => {
-                    let rhs = rhs.load_scalar(fx);
-                    let rhs_ge_zero =
-                        fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
-                    let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max);
-                    fx.bcx.ins().select(has_overflow, sat_val, val)
-                }
-                _ => unreachable!(),
-            };
-
-            let res = CValue::by_val(val, lhs.layout());
-
+            let res = crate::num::codegen_saturating_int_binop(fx, bin_op, lhs, rhs);
             ret.write_cvalue(fx, res);
         }
         sym::rotate_left => {
@@ -819,8 +813,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
         sym::ptr_guaranteed_cmp => {
             intrinsic_args!(fx, args => (a, b); intrinsic);
 
-            let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b);
-            ret.write_cvalue(fx, val);
+            let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b).load_scalar(fx);
+            ret.write_cvalue(fx, CValue::by_val(val, fx.layout_of(fx.tcx.types.u8)));
         }
 
         sym::caller_location => {
@@ -1206,7 +1200,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
             // FIXME once unwinding is supported, change this to actually catch panics
             let f_sig = fx.bcx.func.import_signature(Signature {
                 call_conv: fx.target_config.default_call_conv,
-                params: vec![AbiParam::new(fx.bcx.func.dfg.value_type(data))],
+                params: vec![AbiParam::new(pointer_ty(fx.tcx))],
                 returns: vec![],
             });
 
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 1f358b1bbb9..51fce8c854b 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -2,6 +2,7 @@
 
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_span::Symbol;
+use rustc_target::abi::Endian;
 
 use super::*;
 use crate::prelude::*;
@@ -26,7 +27,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
     span: Span,
 ) {
     match intrinsic {
-        sym::simd_cast => {
+        sym::simd_as | sym::simd_cast => {
             intrinsic_args!(fx, args => (a); intrinsic);
 
             if !a.layout().ty.is_simd() {
@@ -162,6 +163,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                     }
                 }
             } else {
+                // FIXME remove this case
                 intrinsic.as_str()["simd_shuffle".len()..].parse().unwrap()
             };
 
@@ -650,8 +652,128 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             }
         }
 
-        // simd_saturating_*
-        // simd_bitmask
+        sym::simd_select_bitmask => {
+            intrinsic_args!(fx, args => (m, a, b); intrinsic);
+
+            if !a.layout().ty.is_simd() {
+                report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
+                return;
+            }
+            assert_eq!(a.layout(), b.layout());
+
+            let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
+            let lane_layout = fx.layout_of(lane_ty);
+
+            let m = m.load_scalar(fx);
+
+            for lane in 0..lane_count {
+                let m_lane = fx.bcx.ins().ushr_imm(m, u64::from(lane) as i64);
+                let m_lane = fx.bcx.ins().band_imm(m_lane, 1);
+                let a_lane = a.value_lane(fx, lane).load_scalar(fx);
+                let b_lane = b.value_lane(fx, lane).load_scalar(fx);
+
+                let m_lane = fx.bcx.ins().icmp_imm(IntCC::Equal, m_lane, 0);
+                let res_lane =
+                    CValue::by_val(fx.bcx.ins().select(m_lane, b_lane, a_lane), lane_layout);
+
+                ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
+            }
+        }
+
+        sym::simd_bitmask => {
+            intrinsic_args!(fx, args => (a); intrinsic);
+
+            let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
+            let lane_clif_ty = fx.clif_type(lane_ty).unwrap();
+
+            // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
+            // vector mask and returns the most significant bit (MSB) of each lane in the form
+            // of either:
+            // * an unsigned integer
+            // * an array of `u8`
+            // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
+            //
+            // The bit order of the result depends on the byte endianness, LSB-first for little
+            // endian and MSB-first for big endian.
+            let expected_int_bits = lane_count.max(8);
+            let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64);
+
+            match lane_ty.kind() {
+                ty::Int(_) | ty::Uint(_) => {}
+                _ => {
+                    fx.tcx.sess.span_fatal(
+                        span,
+                        &format!(
+                            "invalid monomorphization of `simd_bitmask` intrinsic: \
+                            vector argument `{}`'s element type `{}`, expected integer element \
+                            type",
+                            a.layout().ty,
+                            lane_ty
+                        ),
+                    );
+                }
+            }
+
+            let res_type =
+                Type::int_with_byte_size(u16::try_from(expected_bytes).unwrap()).unwrap();
+            let mut res = fx.bcx.ins().iconst(res_type, 0);
+
+            let lanes = match fx.tcx.sess.target.endian {
+                Endian::Big => Box::new(0..lane_count) as Box<dyn Iterator<Item = u64>>,
+                Endian::Little => Box::new((0..lane_count).rev()) as Box<dyn Iterator<Item = u64>>,
+            };
+            for lane in lanes {
+                let a_lane = a.value_lane(fx, lane).load_scalar(fx);
+
+                // extract sign bit of an int
+                let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_clif_ty.bits() - 1));
+
+                // shift sign bit into result
+                let a_lane_sign = clif_intcast(fx, a_lane_sign, res_type, false);
+                res = fx.bcx.ins().ishl_imm(res, 1);
+                res = fx.bcx.ins().bor(res, a_lane_sign);
+            }
+
+            match ret.layout().ty.kind() {
+                ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {}
+                ty::Array(elem, len)
+                    if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
+                        && len.try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all())
+                            == Some(expected_bytes) => {}
+                _ => {
+                    fx.tcx.sess.span_fatal(
+                        span,
+                        &format!(
+                            "invalid monomorphization of `simd_bitmask` intrinsic: \
+                            cannot return `{}`, expected `u{}` or `[u8; {}]`",
+                            ret.layout().ty,
+                            expected_int_bits,
+                            expected_bytes
+                        ),
+                    );
+                }
+            }
+
+            let res = CValue::by_val(res, ret.layout());
+            ret.write_cvalue(fx, res);
+        }
+
+        sym::simd_saturating_add | sym::simd_saturating_sub => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
+
+            let bin_op = match intrinsic {
+                sym::simd_saturating_add => BinOp::Add,
+                sym::simd_saturating_sub => BinOp::Sub,
+                _ => unreachable!(),
+            };
+
+            // FIXME use vector instructions when possible
+            simd_pair_for_each_lane_typed(fx, x, y, ret, &|fx, x_lane, y_lane| {
+                crate::num::codegen_saturating_int_binop(fx, bin_op, x_lane, y_lane)
+            });
+        }
+
+        // simd_arith_offset
         // simd_scatter
         // simd_gather
         _ => {
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 913414e7618..629d79d5012 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -96,8 +96,8 @@ mod prelude {
     pub(crate) use cranelift_codegen::ir::function::Function;
     pub(crate) use cranelift_codegen::ir::types;
     pub(crate) use cranelift_codegen::ir::{
-        AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc,
-        StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value,
+        AbiParam, Block, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc, StackSlot,
+        StackSlotData, StackSlotKind, TrapCode, Type, Value,
     };
     pub(crate) use cranelift_codegen::isa::{self, CallConv};
     pub(crate) use cranelift_codegen::Context;
@@ -251,7 +251,6 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
 
     let mut flags_builder = settings::builder();
     flags_builder.enable("is_pic").unwrap();
-    flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
     let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
     flags_builder.set("enable_verifier", enable_verifier).unwrap();
     flags_builder.set("regalloc_checker", enable_verifier).unwrap();
@@ -279,6 +278,15 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
         }
     }
 
+    if target_triple.architecture == target_lexicon::Architecture::X86_64 {
+        // Windows depends on stack probes to grow the committed part of the stack
+        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 x86_64
+        flags_builder.set("enable_probestack", "false").unwrap();
+    }
+
     let flags = settings::Flags::new(flags_builder);
 
     let isa_builder = match sess.opts.cg.target_cpu.as_deref() {
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index 3c024a84d90..cae6312a607 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -75,7 +75,7 @@ pub(crate) fn maybe_create_entry_wrapper(
         let main_func_id = m.declare_function(main_name, Linkage::Import, &main_sig).unwrap();
 
         let mut ctx = Context::new();
-        ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig);
+        ctx.func.signature = cmain_sig;
         {
             let mut func_ctx = FunctionBuilderContext::new();
             let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index 4ce8adb182e..ecbab408ded 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -150,18 +150,12 @@ pub(crate) fn codegen_int_binop<'tcx>(
         BinOp::BitXor => b.bxor(lhs, rhs),
         BinOp::BitAnd => b.band(lhs, rhs),
         BinOp::BitOr => b.bor(lhs, rhs),
-        BinOp::Shl => {
-            let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
-            let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
-            fx.bcx.ins().ishl(lhs, actual_shift)
-        }
+        BinOp::Shl => b.ishl(lhs, rhs),
         BinOp::Shr => {
-            let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
-            let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
             if signed {
-                fx.bcx.ins().sshr(lhs, actual_shift)
+                b.sshr(lhs, rhs)
             } else {
-                fx.bcx.ins().ushr(lhs, actual_shift)
+                b.ushr(lhs, rhs)
             }
         }
         // Compare binops handles by `codegen_binop`.
@@ -279,22 +273,15 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
             }
         }
         BinOp::Shl => {
-            let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
-            let masked_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
-            let val = fx.bcx.ins().ishl(lhs, masked_shift);
+            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 lhs_ty = fx.bcx.func.dfg.value_type(lhs);
-            let masked_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
-            let val = if !signed {
-                fx.bcx.ins().ushr(lhs, masked_shift)
-            } else {
-                fx.bcx.ins().sshr(lhs, masked_shift)
-            };
+            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);
@@ -309,6 +296,42 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
     CValue::by_val_pair(res, has_overflow, out_layout)
 }
 
+pub(crate) fn codegen_saturating_int_binop<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    bin_op: BinOp,
+    lhs: CValue<'tcx>,
+    rhs: CValue<'tcx>,
+) -> CValue<'tcx> {
+    assert_eq!(lhs.layout().ty, rhs.layout().ty);
+
+    let signed = type_sign(lhs.layout().ty);
+    let clif_ty = fx.clif_type(lhs.layout().ty).unwrap();
+    let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed);
+
+    let checked_res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs);
+    let (val, has_overflow) = checked_res.load_scalar_pair(fx);
+
+    let val = match (bin_op, signed) {
+        (BinOp::Add, false) => fx.bcx.ins().select(has_overflow, max, val),
+        (BinOp::Sub, false) => fx.bcx.ins().select(has_overflow, min, val),
+        (BinOp::Add, true) => {
+            let rhs = rhs.load_scalar(fx);
+            let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
+            let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
+            fx.bcx.ins().select(has_overflow, sat_val, val)
+        }
+        (BinOp::Sub, true) => {
+            let rhs = rhs.load_scalar(fx);
+            let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
+            let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max);
+            fx.bcx.ins().select(has_overflow, sat_val, val)
+        }
+        _ => unreachable!(),
+    };
+
+    CValue::by_val(val, lhs.layout())
+}
+
 pub(crate) fn codegen_float_binop<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     bin_op: BinOp,
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index dd9d891ddbd..9c88f7dbcda 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -25,7 +25,12 @@ pub(crate) fn unsized_info<'tcx>(
             .bcx
             .ins()
             .iconst(fx.pointer_type, len.eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64),
-        (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+        (
+            &ty::Dynamic(ref data_a, _, src_dyn_kind),
+            &ty::Dynamic(ref data_b, _, target_dyn_kind),
+        ) => {
+            assert_eq!(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() {
@@ -101,6 +106,21 @@ fn unsize_ptr<'tcx>(
     }
 }
 
+/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type.
+pub(crate) fn cast_to_dyn_star<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    src: Value,
+    src_ty_and_layout: TyAndLayout<'tcx>,
+    dst_ty: Ty<'tcx>,
+    old_info: Option<Value>,
+) -> (Value, Value) {
+    assert!(
+        matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
+        "destination type must be a dyn*"
+    );
+    (src, unsized_info(fx, src_ty_and_layout.ty, dst_ty, old_info))
+}
+
 /// Coerce `src`, which is a reference to a value of type `src_ty`,
 /// to a value of type `dst_ty` and store the result in `dst`
 pub(crate) fn coerce_unsized_into<'tcx>(
@@ -147,6 +167,24 @@ pub(crate) fn coerce_unsized_into<'tcx>(
     }
 }
 
+pub(crate) fn coerce_dyn_star<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    src: CValue<'tcx>,
+    dst: CPlace<'tcx>,
+) {
+    let (data, extra) = if let ty::Dynamic(_, _, ty::DynStar) = src.layout().ty.kind() {
+        let (data, vtable) = src.load_scalar_pair(fx);
+        (data, Some(vtable))
+    } else {
+        let data = src.load_scalar(fx);
+        (data, None)
+    };
+
+    let (data, vtable) = cast_to_dyn_star(fx, data, src.layout(), dst.layout().ty, extra);
+
+    dst.write_cvalue(fx, CValue::by_val_pair(data, vtable, dst.layout()));
+}
+
 // Adapted from https://github.com/rust-lang/rust/blob/2a663555ddf36f6b041445894a8c175cd1bc718c/src/librustc_codegen_ssa/glue.rs
 
 pub(crate) fn size_and_align_of_dst<'tcx>(
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 3fa3e3657cb..c3dfbd37279 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -107,6 +107,50 @@ impl<'tcx> CValue<'tcx> {
         }
     }
 
+    // FIXME remove
+    // Forces the data value of a dyn* value to the stack and returns a pointer to it as well as the
+    // vtable pointer.
+    pub(crate) fn dyn_star_force_data_on_stack(
+        self,
+        fx: &mut FunctionCx<'_, '_, 'tcx>,
+    ) -> (Value, Value) {
+        assert!(self.1.ty.is_dyn_star());
+
+        match self.0 {
+            CValueInner::ByRef(ptr, None) => {
+                let (a_scalar, b_scalar) = match self.1.abi {
+                    Abi::ScalarPair(a, b) => (a, b),
+                    _ => unreachable!("dyn_star_force_data_on_stack({:?})", self),
+                };
+                let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
+                let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar);
+                let mut flags = MemFlags::new();
+                flags.set_notrap();
+                let vtable = ptr.offset(fx, b_offset).load(fx, clif_ty2, flags);
+                (ptr.get_addr(fx), vtable)
+            }
+            CValueInner::ByValPair(data, vtable) => {
+                let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
+                    kind: StackSlotKind::ExplicitSlot,
+                    // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
+                    // specify stack slot alignment.
+                    size: (u32::try_from(fx.target_config.pointer_type().bytes()).unwrap() + 15)
+                        / 16
+                        * 16,
+                });
+                let data_ptr = Pointer::stack_slot(stack_slot);
+                let mut flags = MemFlags::new();
+                flags.set_notrap();
+                data_ptr.store(fx, data, flags);
+
+                (data_ptr.get_addr(fx), vtable)
+            }
+            CValueInner::ByRef(_, Some(_)) | CValueInner::ByVal(_) => {
+                unreachable!("dyn_star_force_data_on_stack({:?})", self)
+            }
+        }
+    }
+
     pub(crate) fn try_to_ptr(self) -> Option<(Pointer, Option<Value>)> {
         match self.0 {
             CValueInner::ByRef(ptr, meta) => Some((ptr, meta)),
@@ -236,6 +280,10 @@ impl<'tcx> CValue<'tcx> {
         crate::unsize::coerce_unsized_into(fx, self, dest);
     }
 
+    pub(crate) fn coerce_dyn_star(self, fx: &mut FunctionCx<'_, '_, 'tcx>, dest: CPlace<'tcx>) {
+        crate::unsize::coerce_dyn_star(fx, self, dest);
+    }
+
     /// If `ty` is signed, `const_val` must already be sign extended.
     pub(crate) fn const_val(
         fx: &mut FunctionCx<'_, '_, 'tcx>,
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 36b3725ef42..f04fb82de8c 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -45,12 +45,26 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     arg: CValue<'tcx>,
     idx: usize,
-) -> (Value, Value) {
-    let (ptr, vtable) = if let Abi::ScalarPair(_, _) = arg.layout().abi {
-        arg.load_scalar_pair(fx)
-    } else {
-        let (ptr, vtable) = arg.try_to_ptr().unwrap();
-        (ptr.get_addr(fx), vtable.unwrap())
+) -> (Pointer, Value) {
+    let (ptr, vtable) = 'block: {
+        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);
+                let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout);
+                let ptr = dyn_star.place_field(fx, mir::Field::new(0)).to_ptr();
+                let vtable =
+                    dyn_star.place_field(fx, mir::Field::new(1)).to_cvalue(fx).load_scalar(fx);
+                break 'block (ptr, vtable);
+            }
+        }
+
+        if let Abi::ScalarPair(_, _) = arg.layout().abi {
+            let (ptr, vtable) = arg.load_scalar_pair(fx);
+            (Pointer::new(ptr), vtable)
+        } else {
+            let (ptr, vtable) = arg.try_to_ptr().unwrap();
+            (ptr, vtable.unwrap())
+        }
     };
 
     let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes();
diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs
index 58efb81e800..e2c9ffe9c1c 100644
--- a/compiler/rustc_codegen_gcc/src/allocator.rs
+++ b/compiler/rustc_codegen_gcc/src/allocator.rs
@@ -7,7 +7,7 @@ use rustc_span::symbol::sym;
 
 use crate::GccContext;
 
-pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
+pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) {
     let context = &mods.context;
     let usize =
         match tcx.sess.target.pointer_width {
@@ -90,14 +90,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
         .collect();
     let func = context.new_function(None, FunctionType::Exported, void, &args, name, false);
 
-    let kind =
-        if has_alloc_error_handler {
-            AllocatorKind::Global
-        }
-        else {
-            AllocatorKind::Default
-        };
-    let callee = kind.fn_name(sym::oom);
+    let callee = alloc_error_handler_kind.fn_name(sym::oom);
     let args: Vec<_> = types.iter().enumerate()
         .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
         .collect();
diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs
index ac0342f6b80..f18ae7ea5e9 100644
--- a/compiler/rustc_codegen_gcc/src/archive.rs
+++ b/compiler/rustc_codegen_gcc/src/archive.rs
@@ -47,6 +47,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
         _lib_name: &str,
         _dll_imports: &[DllImport],
         _tmpdir: &Path,
+        _is_direct_dependency: bool,
     ) -> PathBuf {
         unimplemented!();
     }
diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs
index d7816e395c8..15ad90f9043 100644
--- a/compiler/rustc_codegen_gcc/src/errors.rs
+++ b/compiler/rustc_codegen_gcc/src/errors.rs
@@ -17,7 +17,7 @@ impl IntoDiagnosticArg for ExitCode {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::ranlib_failure)]
+#[diag(codegen_gcc_ranlib_failure)]
 pub(crate) struct RanlibFailure {
     exit_code: ExitCode,
 }
@@ -29,7 +29,7 @@ impl RanlibFailure {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_basic_integer, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_basic_integer, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationBasicInteger<'a> {
     #[primary_span]
     pub span: Span,
@@ -38,7 +38,7 @@ pub(crate) struct InvalidMonomorphizationBasicInteger<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_invalid_float_vector, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_invalid_float_vector, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> {
     #[primary_span]
     pub span: Span,
@@ -48,7 +48,7 @@ pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_not_float, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_not_float, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationNotFloat<'a> {
     #[primary_span]
     pub span: Span,
@@ -57,7 +57,7 @@ pub(crate) struct InvalidMonomorphizationNotFloat<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_unrecognized, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_unrecognized, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationUnrecognized {
     #[primary_span]
     pub span: Span,
@@ -65,7 +65,7 @@ pub(crate) struct InvalidMonomorphizationUnrecognized {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_expected_signed_unsigned, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_expected_signed_unsigned, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> {
     #[primary_span]
     pub span: Span,
@@ -75,7 +75,7 @@ pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_unsupported_element, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_unsupported_element, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> {
     #[primary_span]
     pub span: Span,
@@ -86,7 +86,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_invalid_bitmask, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_invalid_bitmask, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> {
     #[primary_span]
     pub span: Span,
@@ -97,7 +97,7 @@ pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_simd_shuffle, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_simd_shuffle, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> {
     #[primary_span]
     pub span: Span,
@@ -106,7 +106,7 @@ pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_expected_simd, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_expected_simd, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> {
     #[primary_span]
     pub span: Span,
@@ -116,7 +116,7 @@ pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_mask_type, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_mask_type, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationMaskType<'a> {
     #[primary_span]
     pub span: Span,
@@ -125,7 +125,7 @@ pub(crate) struct InvalidMonomorphizationMaskType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_return_length, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_return_length, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationReturnLength<'a> {
     #[primary_span]
     pub span: Span,
@@ -136,7 +136,7 @@ pub(crate) struct InvalidMonomorphizationReturnLength<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_return_length_input_type, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_return_length_input_type, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> {
     #[primary_span]
     pub span: Span,
@@ -148,7 +148,7 @@ pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_return_element, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_return_element, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationReturnElement<'a> {
     #[primary_span]
     pub span: Span,
@@ -160,7 +160,7 @@ pub(crate) struct InvalidMonomorphizationReturnElement<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_return_type, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_return_type, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationReturnType<'a> {
     #[primary_span]
     pub span: Span,
@@ -171,7 +171,7 @@ pub(crate) struct InvalidMonomorphizationReturnType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_inserted_type, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_inserted_type, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationInsertedType<'a> {
     #[primary_span]
     pub span: Span,
@@ -182,7 +182,7 @@ pub(crate) struct InvalidMonomorphizationInsertedType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_return_integer_type, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_return_integer_type, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> {
     #[primary_span]
     pub span: Span,
@@ -192,7 +192,7 @@ pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_mismatched_lengths, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_mismatched_lengths, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationMismatchedLengths {
     #[primary_span]
     pub span: Span,
@@ -202,7 +202,7 @@ pub(crate) struct InvalidMonomorphizationMismatchedLengths {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_unsupported_cast, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_unsupported_cast, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> {
     #[primary_span]
     pub span: Span,
@@ -214,7 +214,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_unsupported_operation, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_unsupported_operation, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> {
     #[primary_span]
     pub span: Span,
@@ -224,18 +224,18 @@ pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::linkage_const_or_mut_type)]
+#[diag(codegen_gcc_linkage_const_or_mut_type)]
 pub(crate) struct LinkageConstOrMutType {
     #[primary_span]
     pub span: Span
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::lto_not_supported)]
+#[diag(codegen_gcc_lto_not_supported)]
 pub(crate) struct LTONotSupported;
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::unwinding_inline_asm)]
+#[diag(codegen_gcc_unwinding_inline_asm)]
 pub(crate) struct UnwindingInlineAsm {
     #[primary_span]
     pub span: Span
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index accd02ab002..dd0daf2c38b 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -153,11 +153,11 @@ impl CodegenBackend for GccCodegenBackend {
 }
 
 impl ExtraBackendMethods for GccCodegenBackend {
-    fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) -> Self::Module {
+    fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module {
         let mut mods = GccContext {
             context: Context::default(),
         };
-        unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); }
+        unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); }
         mods
     }
 
diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs
index 46abbb553bf..38c1eac7adf 100644
--- a/compiler/rustc_codegen_gcc/tests/run/asm.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: 0
 
-#![feature(asm_const, asm_sym)]
+#![feature(asm_const)]
 
 use std::arch::{asm, global_asm};
 
-global_asm!("
+global_asm!(
+    "
     .global add_asm
 add_asm:
      mov rax, rdi
@@ -132,7 +133,9 @@ fn main() {
     assert_eq!(x, 43);
 
     // check sym fn
-    extern "C" fn foo() -> u64 { 42 }
+    extern "C" fn foo() -> u64 {
+        42
+    }
     let x: u64;
     unsafe {
         asm!("call {}", sym foo, lateout("rax") x);
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 72961ae888e..fed56cdd438 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -15,7 +15,7 @@ pub(crate) unsafe fn codegen(
     module_llvm: &mut ModuleLlvm,
     module_name: &str,
     kind: AllocatorKind,
-    has_alloc_error_handler: bool,
+    alloc_error_handler_kind: AllocatorKind,
 ) {
     let llcx = &*module_llvm.llcx;
     let llmod = module_llvm.llmod();
@@ -117,8 +117,7 @@ pub(crate) unsafe fn codegen(
         attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
     }
 
-    let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default };
-    let callee = kind.fn_name(sym::oom);
+    let callee = alloc_error_handler_kind.fn_name(sym::oom);
     let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
     // -> ! DIFlagNoReturn
     attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 0254f982948..88a4f62d93d 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -560,6 +560,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
                 format!("{{{}}}", reg.name())
             }
         }
+        // The constraints can be retrieved from
+        // https://llvm.org/docs/LangRef.html#supported-constraint-code-list
         InlineAsmRegOrRegClass::RegClass(reg) => match reg {
             InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w",
@@ -633,6 +635,8 @@ fn modifier_to_llvm(
     reg: InlineAsmRegClass,
     modifier: Option<char>,
 ) -> Option<char> {
+    // The modifiers can be retrieved from
+    // https://llvm.org/docs/LangRef.html#asm-template-argument-modifiers
     match reg {
         InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier,
         InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg)
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 20a063f80fd..082665bba38 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -165,10 +165,12 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
         lib_name: &str,
         dll_imports: &[DllImport],
         tmpdir: &Path,
+        is_direct_dependency: bool,
     ) -> PathBuf {
+        let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
         let output_path = {
             let mut output_path: PathBuf = tmpdir.to_path_buf();
-            output_path.push(format!("{}_imports", lib_name));
+            output_path.push(format!("{}{}", lib_name, name_suffix));
             output_path.with_extension("lib")
         };
 
@@ -195,7 +197,8 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
             // that loaded but crashed with an AV upon calling one of the imported
             // functions.  Therefore, use binutils to create the import library instead,
             // by writing a .DEF file to the temp dir and calling binutils's dlltool.
-            let def_file_path = tmpdir.join(format!("{}_imports", lib_name)).with_extension("def");
+            let def_file_path =
+                tmpdir.join(format!("{}{}", lib_name, name_suffix)).with_extension("def");
 
             let def_file_content = format!(
                 "EXPORTS\n{}",
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index cef7bf1e803..a49cc7f8d66 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -32,8 +32,8 @@ pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin";
 
 pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
     match crate_type {
-        CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => true,
-        CrateType::Dylib | CrateType::Rlib | CrateType::ProcMacro => false,
+        CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true,
+        CrateType::Rlib | CrateType::ProcMacro => false,
     }
 }
 
@@ -73,17 +73,6 @@ fn prepare_lto(
     // with either fat or thin LTO
     let mut upstream_modules = Vec::new();
     if cgcx.lto != Lto::ThinLocal {
-        if cgcx.opts.cg.prefer_dynamic {
-            diag_handler
-                .struct_err("cannot prefer dynamic linking when performing LTO")
-                .note(
-                    "only 'staticlib', 'bin', and 'cdylib' outputs are \
-                               supported with LTO",
-                )
-                .emit();
-            return Err(FatalError);
-        }
-
         // Make sure we actually can run LTO
         for crate_type in cgcx.crate_types.iter() {
             if !crate_type_allows_lto(*crate_type) {
@@ -92,9 +81,25 @@ fn prepare_lto(
                                             static library outputs",
                 );
                 return Err(e);
+            } else if *crate_type == CrateType::Dylib {
+                if !cgcx.opts.unstable_opts.dylib_lto {
+                    return Err(diag_handler
+                        .fatal("lto cannot be used for `dylib` crate type without `-Zdylib-lto`"));
+                }
             }
         }
 
+        if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
+            diag_handler
+                .struct_err("cannot prefer dynamic linking when performing LTO")
+                .note(
+                    "only 'staticlib', 'bin', and 'cdylib' outputs are \
+                               supported with LTO",
+                )
+                .emit();
+            return Err(FatalError);
+        }
+
         for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
             let exported_symbols =
                 cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO");
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index db526746fa7..11053a8f6c4 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -537,7 +537,7 @@ pub(crate) fn link(
     mut modules: Vec<ModuleCodegen<ModuleLlvm>>,
 ) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
     use super::lto::{Linker, ModuleBuffer};
-    // Sort the modules by name to ensure to ensure deterministic behavior.
+    // Sort the modules by name to ensure deterministic behavior.
     modules.sort_by(|a, b| a.name.cmp(&b.name));
     let (first, elements) =
         modules.split_first().expect("Bug! modules must contain at least one module.");
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index fca43a0d86d..9cb36ce7f18 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -365,11 +365,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 Int(I64) => "llvm.ssub.with.overflow.i64",
                 Int(I128) => "llvm.ssub.with.overflow.i128",
 
-                Uint(U8) => "llvm.usub.with.overflow.i8",
-                Uint(U16) => "llvm.usub.with.overflow.i16",
-                Uint(U32) => "llvm.usub.with.overflow.i32",
-                Uint(U64) => "llvm.usub.with.overflow.i64",
-                Uint(U128) => "llvm.usub.with.overflow.i128",
+                Uint(_) => {
+                    // Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these
+                    // to be the canonical form. It will attempt to reform llvm.usub.with.overflow
+                    // in the backend if profitable.
+                    let sub = self.sub(lhs, rhs);
+                    let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs);
+                    return (sub, cmp);
+                }
 
                 _ => unreachable!(),
             },
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index b83c1e8f08f..6f0d1b7ce84 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -179,7 +179,8 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
             // MinGW: For backward compatibility we rely on the linker to decide whether it
             // should use dllimport for functions.
             if cx.use_dll_storage_attrs
-                && tcx.is_dllimport_foreign_item(instance_def_id)
+                && let Some(library) = tcx.native_library(instance_def_id)
+                && library.kind.is_dllimport()
                 && !matches!(tcx.sess.target.env.as_ref(), "gnu" | "uclibc")
             {
                 llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index ee2fc65e37b..dd3c43ba5ca 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -332,7 +332,10 @@ impl<'ll> CodegenCx<'ll, '_> {
             }
         }
 
-        if self.use_dll_storage_attrs && self.tcx.is_dllimport_foreign_item(def_id) {
+        if self.use_dll_storage_attrs
+            && let Some(library) = self.tcx.native_library(def_id)
+            && library.kind.is_dllimport()
+        {
             // For foreign (native) libs we know the exact storage type to use.
             unsafe {
                 llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 0d1df6fb1ac..433f043209e 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -129,7 +129,7 @@ impl CoverageMapGenerator {
             // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
             // requires setting the first filename to the compilation directory.
             // Since rustc generates coverage maps with relative paths, the
-            // compilation directory can be combined with the the relative paths
+            // compilation directory can be combined with the relative paths
             // to get absolute paths, if needed.
             let working_dir = tcx
                 .sess
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 89c7e51d09e..d51aced85df 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -108,11 +108,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
         tcx: TyCtxt<'tcx>,
         module_name: &str,
         kind: AllocatorKind,
-        has_alloc_error_handler: bool,
+        alloc_error_handler_kind: AllocatorKind,
     ) -> ModuleLlvm {
         let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
         unsafe {
-            allocator::codegen(tcx, &mut module_llvm, module_name, kind, has_alloc_error_handler);
+            allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind);
         }
         module_llvm
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index bad58d0a8a0..bb76ca5d2b9 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -25,6 +25,7 @@ pub trait ArchiveBuilderBuilder {
         lib_name: &str,
         dll_imports: &[DllImport],
         tmpdir: &Path,
+        is_direct_dependency: bool,
     ) -> PathBuf;
 
     fn extract_bundled_libs(
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 95e72184ff0..0dc0dee862c 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -11,7 +11,7 @@ use rustc_metadata::find_native_static_library;
 use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME};
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
-use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
+use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Lto, Strip};
 use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
 use rustc_session::cstore::DllImport;
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
@@ -39,6 +39,7 @@ use cc::windows_registry;
 use regex::Regex;
 use tempfile::Builder as TempFileBuilder;
 
+use itertools::Itertools;
 use std::borrow::Borrow;
 use std::cell::OnceCell;
 use std::collections::BTreeSet;
@@ -208,11 +209,29 @@ pub fn link_binary<'a>(
 }
 
 pub fn each_linked_rlib(
+    sess: &Session,
     info: &CrateInfo,
     f: &mut dyn FnMut(CrateNum, &Path),
 ) -> Result<(), errors::LinkRlibError> {
     let crates = info.used_crates.iter();
     let mut fmts = None;
+
+    let lto_active = matches!(sess.lto(), Lto::Fat | Lto::Thin);
+    if lto_active {
+        for combination in info.dependency_formats.iter().combinations(2) {
+            let (ty1, list1) = &combination[0];
+            let (ty2, list2) = &combination[1];
+            if list1 != list2 {
+                return Err(errors::LinkRlibError::IncompatibleDependencyFormats {
+                    ty1: format!("{ty1:?}"),
+                    ty2: format!("{ty2:?}"),
+                    list1: format!("{list1:?}"),
+                    list2: format!("{list2:?}"),
+                });
+            }
+        }
+    }
+
     for (ty, list) in info.dependency_formats.iter() {
         match ty {
             CrateType::Executable
@@ -222,6 +241,10 @@ pub fn each_linked_rlib(
                 fmts = Some(list);
                 break;
             }
+            CrateType::Dylib if lto_active => {
+                fmts = Some(list);
+                break;
+            }
             _ => {}
         }
     }
@@ -368,13 +391,14 @@ fn link_rlib<'a>(
     }
 
     for (raw_dylib_name, raw_dylib_imports) in
-        collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
+        collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())?
     {
         let output_path = archive_builder_builder.create_dll_import_lib(
             sess,
             &raw_dylib_name,
             &raw_dylib_imports,
             tmpdir.as_ref(),
+            true,
         );
 
         ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
@@ -426,9 +450,9 @@ fn link_rlib<'a>(
 /// then the CodegenResults value contains one NativeLib instance for each block.  However, the
 /// linker appears to expect only a single import library for each library used, so we need to
 /// collate the symbols together by library name before generating the import libraries.
-fn collate_raw_dylibs(
-    sess: &Session,
-    used_libraries: &[NativeLib],
+fn collate_raw_dylibs<'a, 'b>(
+    sess: &'a Session,
+    used_libraries: impl IntoIterator<Item = &'b NativeLib>,
 ) -> Result<Vec<(String, Vec<DllImport>)>, ErrorGuaranteed> {
     // Use index maps to preserve original order of imports and libraries.
     let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
@@ -490,7 +514,7 @@ fn link_staticlib<'a>(
     )?;
     let mut all_native_libs = vec![];
 
-    let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| {
+    let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| {
         let name = codegen_results.crate_info.crate_name[&cnum];
         let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
 
@@ -1011,16 +1035,36 @@ fn link_natively<'a>(
 
     if sess.target.is_like_osx {
         match (strip, crate_type) {
-            (Strip::Debuginfo, _) => strip_symbols_in_osx(sess, &out_filename, Some("-S")),
+            (Strip::Debuginfo, _) => {
+                strip_symbols_with_external_utility(sess, "strip", &out_filename, Some("-S"))
+            }
             // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
             (Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
-                strip_symbols_in_osx(sess, &out_filename, Some("-x"))
+                strip_symbols_with_external_utility(sess, "strip", &out_filename, Some("-x"))
+            }
+            (Strip::Symbols, _) => {
+                strip_symbols_with_external_utility(sess, "strip", &out_filename, None)
             }
-            (Strip::Symbols, _) => strip_symbols_in_osx(sess, &out_filename, None),
             (Strip::None, _) => {}
         }
     }
 
+    if sess.target.os == "illumos" {
+        // Many illumos systems will have both the native 'strip' utility and
+        // the GNU one. Use the native version explicitly and do not rely on
+        // what's in the path.
+        let stripcmd = "/usr/bin/strip";
+        match strip {
+            // Always preserve the symbol table (-x).
+            Strip::Debuginfo => {
+                strip_symbols_with_external_utility(sess, stripcmd, &out_filename, Some("-x"))
+            }
+            // Strip::Symbols is handled via the --strip-all linker option.
+            Strip::Symbols => {}
+            Strip::None => {}
+        }
+    }
+
     Ok(())
 }
 
@@ -1032,8 +1076,13 @@ fn strip_value(sess: &Session) -> Strip {
     }
 }
 
-fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Option<&str>) {
-    let mut cmd = Command::new("strip");
+fn strip_symbols_with_external_utility<'a>(
+    sess: &'a Session,
+    util: &str,
+    out_filename: &Path,
+    option: Option<&str>,
+) {
+    let mut cmd = Command::new(util);
     if let Some(option) = option {
         cmd.arg(option);
     }
@@ -1044,14 +1093,14 @@ fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Opti
                 let mut output = prog.stderr.clone();
                 output.extend_from_slice(&prog.stdout);
                 sess.struct_warn(&format!(
-                    "stripping debug info with `strip` failed: {}",
-                    prog.status
+                    "stripping debug info with `{}` failed: {}",
+                    util, prog.status
                 ))
                 .note(&escape_string(&output))
                 .emit();
             }
         }
-        Err(e) => sess.fatal(&format!("unable to run `strip`: {}", e)),
+        Err(e) => sess.fatal(&format!("unable to run `{}`: {}", util, e)),
     }
 }
 
@@ -2020,13 +2069,43 @@ fn linker_with_args<'a>(
 
     // Link with the import library generated for any raw-dylib functions.
     for (raw_dylib_name, raw_dylib_imports) in
-        collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
+        collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())?
+    {
+        cmd.add_object(&archive_builder_builder.create_dll_import_lib(
+            sess,
+            &raw_dylib_name,
+            &raw_dylib_imports,
+            tmpdir,
+            true,
+        ));
+    }
+    // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
+    // they are used within inlined functions or instantiated generic functions. We do this *after*
+    // handling the raw-dylib symbols in the current crate to make sure that those are chosen first
+    // by the linker.
+    let (_, dependency_linkage) = codegen_results
+        .crate_info
+        .dependency_formats
+        .iter()
+        .find(|(ty, _)| *ty == crate_type)
+        .expect("failed to find crate type in dependency format list");
+    let native_libraries_from_nonstatics = codegen_results
+        .crate_info
+        .native_libraries
+        .iter()
+        .filter_map(|(cnum, libraries)| {
+            (dependency_linkage[cnum.as_usize() - 1] != Linkage::Static).then(|| libraries)
+        })
+        .flatten();
+    for (raw_dylib_name, raw_dylib_imports) in
+        collate_raw_dylibs(sess, native_libraries_from_nonstatics)?
     {
         cmd.add_object(&archive_builder_builder.create_dll_import_lib(
             sess,
             &raw_dylib_name,
             &raw_dylib_imports,
             tmpdir,
+            false,
         ));
     }
 
@@ -2690,7 +2769,7 @@ fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
     }
 }
 
-fn are_upstream_rust_objects_already_included(sess: &Session) -> bool {
+pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool {
     match sess.lto() {
         config::Lto::Fat => true,
         config::Lto::Thin => {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index bad22ccb1fe..c49b19bdf00 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -610,7 +610,13 @@ impl<'a> Linker for GccLinker<'a> {
         match strip {
             Strip::None => {}
             Strip::Debuginfo => {
-                self.linker_arg("--strip-debug");
+                // The illumos linker does not support --strip-debug although
+                // it does support --strip-all as a compatibility alias for -s.
+                // The --strip-debug case is handled by running an external
+                // `strip` utility as a separate step after linking.
+                if self.sess.target.os != "illumos" {
+                    self.linker_arg("--strip-debug");
+                }
             }
             Strip::Symbols => {
                 self.linker_arg("--strip-all");
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index b92e146bee2..99ddd176478 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -117,6 +117,10 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
         "riscv32" => Architecture::Riscv32,
         "riscv64" => Architecture::Riscv64,
         "sparc64" => Architecture::Sparc64,
+        "avr" => Architecture::Avr,
+        "msp430" => Architecture::Msp430,
+        "hexagon" => Architecture::Hexagon,
+        "bpf" => Architecture::Bpf,
         // Unsupported architecture.
         _ => return None,
     };
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 8d7e2c5cf39..752f6b1ef40 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::{self, SymbolName, TyCtxt};
-use rustc_session::config::CrateType;
+use rustc_session::config::{CrateType, OomStrategy};
 use rustc_target::spec::SanitizerSet;
 
 pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
@@ -76,7 +76,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
             // let it through if it's included statically.
             match tcx.hir().get_by_def_id(def_id) {
                 Node::ForeignItem(..) => {
-                    tcx.is_statically_included_foreign_item(def_id).then_some(def_id)
+                    tcx.native_library(def_id).map_or(false, |library| library.kind.is_statically_included()).then_some(def_id)
                 }
 
                 // Only consider nodes that actually have exported symbols.
@@ -193,8 +193,11 @@ fn exported_symbols_provider_local<'tcx>(
     }
 
     if tcx.allocator_kind(()).is_some() {
-        for method in ALLOCATOR_METHODS {
-            let symbol_name = format!("__rust_{}", method.name);
+        for symbol_name in ALLOCATOR_METHODS
+            .iter()
+            .map(|method| format!("__rust_{}", method.name))
+            .chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()])
+        {
             let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
 
             symbols.push((
@@ -206,6 +209,15 @@ fn exported_symbols_provider_local<'tcx>(
                 },
             ));
         }
+
+        symbols.push((
+            ExportedSymbol::NoDefId(SymbolName::new(tcx, OomStrategy::SYMBOL)),
+            SymbolExportInfo {
+                level: SymbolExportLevel::Rust,
+                kind: SymbolExportKind::Text,
+                used: false,
+            },
+        ));
     }
 
     if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() {
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index a292bfce31e..d0ac016b02e 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -999,6 +999,14 @@ fn start_executing_work<B: ExtraBackendMethods>(
     let coordinator_send = tx_to_llvm_workers;
     let sess = tcx.sess;
 
+    let mut each_linked_rlib_for_lto = Vec::new();
+    drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| {
+        if link::ignored_for_lto(sess, crate_info, cnum) {
+            return;
+        }
+        each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
+    }));
+
     // Compute the set of symbols we need to retain when doing LTO (if we need to)
     let exported_symbols = {
         let mut exported_symbols = FxHashMap::default();
@@ -1020,7 +1028,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
             }
             Lto::Fat | Lto::Thin => {
                 exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
-                for &cnum in tcx.crates(()).iter() {
+                for &(cnum, ref _path) in &each_linked_rlib_for_lto {
                     exported_symbols.insert(cnum, copy_symbols(cnum));
                 }
                 Some(Arc::new(exported_symbols))
@@ -1040,14 +1048,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
         })
         .expect("failed to spawn helper thread");
 
-    let mut each_linked_rlib_for_lto = Vec::new();
-    drop(link::each_linked_rlib(crate_info, &mut |cnum, path| {
-        if link::ignored_for_lto(sess, crate_info, cnum) {
-            return;
-        }
-        each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
-    }));
-
     let ol =
         if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
             // If we know that we won’t be doing codegen, create target machines without optimisation.
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index cb5436fd61a..c1411690f82 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -1,3 +1,4 @@
+use crate::back::link::are_upstream_rust_objects_already_included;
 use crate::back::metadata::create_compressed_metadata_file;
 use crate::back::write::{
     compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
@@ -21,7 +22,6 @@ use rustc_data_structures::sync::ParallelIterator;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::weak_lang_items::WEAK_ITEMS_SYMBOLS;
 use rustc_index::vec::Idx;
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
@@ -38,7 +38,7 @@ use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::Symbol;
 use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
-use rustc_target::abi::{Align, VariantIdx};
+use rustc_target::abi::{Align, Size, VariantIdx};
 
 use std::collections::BTreeSet;
 use std::convert::TryFrom;
@@ -150,7 +150,12 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         (&ty::Array(_, len), &ty::Slice(_)) => {
             cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
         }
-        (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+        (
+            &ty::Dynamic(ref data_a, _, src_dyn_kind),
+            &ty::Dynamic(ref data_b, _, target_dyn_kind),
+        ) => {
+            assert_eq!(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() {
@@ -166,11 +171,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             if let Some(entry_idx) = vptr_entry_idx {
                 let ptr_ty = cx.type_i8p();
                 let ptr_align = cx.tcx().data_layout.pointer_align.abi;
-                let vtable_ptr_ty = cx.scalar_pair_element_backend_type(
-                    cx.layout_of(cx.tcx().mk_mut_ptr(target)),
-                    1,
-                    true,
-                );
+                let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind);
                 let llvtable = bx.pointercast(old_info, bx.type_ptr_to(ptr_ty));
                 let gep = bx.inbounds_gep(
                     ptr_ty,
@@ -186,18 +187,32 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 old_info
             }
         }
-        (_, &ty::Dynamic(ref data, ..)) => {
-            let vtable_ptr_ty = cx.scalar_pair_element_backend_type(
-                cx.layout_of(cx.tcx().mk_mut_ptr(target)),
-                1,
-                true,
-            );
+        (_, &ty::Dynamic(ref data, _, target_dyn_kind)) => {
+            let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind);
             cx.const_ptrcast(meth::get_vtable(cx, source, data.principal()), vtable_ptr_ty)
         }
         _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
     }
 }
 
+// Returns the vtable pointer type of a `dyn` or `dyn*` type
+fn vtable_ptr_ty<'tcx, Cx: CodegenMethods<'tcx>>(
+    cx: &Cx,
+    target: Ty<'tcx>,
+    kind: ty::DynKind,
+) -> <Cx as BackendTypes>::Type {
+    cx.scalar_pair_element_backend_type(
+        cx.layout_of(match kind {
+            // vtable is the second field of `*mut dyn Trait`
+            ty::Dyn => cx.tcx().mk_mut_ptr(target),
+            // vtable is the second field of `dyn* Trait`
+            ty::DynStar => target,
+        }),
+        1,
+        true,
+    )
+}
+
 /// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
 pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
@@ -247,6 +262,29 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 }
 
+/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type.
+pub fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    bx: &mut Bx,
+    src: Bx::Value,
+    src_ty_and_layout: TyAndLayout<'tcx>,
+    dst_ty: Ty<'tcx>,
+    old_info: Option<Bx::Value>,
+) -> (Bx::Value, Bx::Value) {
+    debug!("cast_to_dyn_star: {:?} => {:?}", src_ty_and_layout.ty, dst_ty);
+    assert!(
+        matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
+        "destination type must be a dyn*"
+    );
+    // FIXME(dyn-star): this is probably not the best way to check if this is
+    // a pointer, and really we should ensure that the value is a suitable
+    // pointer earlier in the compilation process.
+    let src = match src_ty_and_layout.pointee_info_at(bx.cx(), Size::ZERO) {
+        Some(_) => bx.ptrtoint(src, bx.cx().type_isize()),
+        None => bx.bitcast(src, bx.type_isize()),
+    };
+    (src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info))
+}
+
 /// Coerces `src`, which is a reference to a value of type `src_ty`,
 /// to a value of type `dst_ty`, and stores the result in `dst`.
 pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
@@ -298,40 +336,26 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
 pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
-    op: hir::BinOpKind,
-    lhs: Bx::Value,
-    rhs: Bx::Value,
-) -> Bx::Value {
-    cast_shift_rhs(bx, op, lhs, rhs)
-}
-
-fn cast_shift_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
-    bx: &mut Bx,
-    op: hir::BinOpKind,
     lhs: Bx::Value,
     rhs: Bx::Value,
 ) -> Bx::Value {
     // Shifts may have any size int on the rhs
-    if op.is_shift() {
-        let mut rhs_llty = bx.cx().val_ty(rhs);
-        let mut lhs_llty = bx.cx().val_ty(lhs);
-        if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
-            rhs_llty = bx.cx().element_type(rhs_llty)
-        }
-        if bx.cx().type_kind(lhs_llty) == TypeKind::Vector {
-            lhs_llty = bx.cx().element_type(lhs_llty)
-        }
-        let rhs_sz = bx.cx().int_width(rhs_llty);
-        let lhs_sz = bx.cx().int_width(lhs_llty);
-        if lhs_sz < rhs_sz {
-            bx.trunc(rhs, lhs_llty)
-        } else if lhs_sz > rhs_sz {
-            // FIXME (#1877: If in the future shifting by negative
-            // values is no longer undefined then this is wrong.
-            bx.zext(rhs, lhs_llty)
-        } else {
-            rhs
-        }
+    let mut rhs_llty = bx.cx().val_ty(rhs);
+    let mut lhs_llty = bx.cx().val_ty(lhs);
+    if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
+        rhs_llty = bx.cx().element_type(rhs_llty)
+    }
+    if bx.cx().type_kind(lhs_llty) == TypeKind::Vector {
+        lhs_llty = bx.cx().element_type(lhs_llty)
+    }
+    let rhs_sz = bx.cx().int_width(rhs_llty);
+    let lhs_sz = bx.cx().int_width(lhs_llty);
+    if lhs_sz < rhs_sz {
+        bx.trunc(rhs, lhs_llty)
+    } else if lhs_sz > rhs_sz {
+        // FIXME (#1877: If in the future shifting by negative
+        // values is no longer undefined then this is wrong.
+        bx.zext(rhs, lhs_llty)
     } else {
         rhs
     }
@@ -614,7 +638,14 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         let llmod_id =
             cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
         let module_llvm = tcx.sess.time("write_allocator_module", || {
-            backend.codegen_allocator(tcx, &llmod_id, kind, tcx.lang_items().oom().is_some())
+            backend.codegen_allocator(
+                tcx,
+                &llmod_id,
+                kind,
+                // If allocator_kind is Some then alloc_error_handler_kind must
+                // also be Some.
+                tcx.alloc_error_handler_kind(()).unwrap(),
+            )
         });
 
         Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator })
@@ -854,18 +885,22 @@ impl CrateInfo {
 
         // Handle circular dependencies in the standard library.
         // See comment before `add_linked_symbol_object` function for the details.
-        // With msvc-like linkers it's both unnecessary (they support circular dependencies),
-        // and causes linking issues (when weak lang item symbols are "privatized" by LTO).
+        // If global LTO is enabled then almost everything (*) is glued into a single object file,
+        // so this logic is not necessary and can cause issues on some targets (due to weak lang
+        // item symbols being "privatized" to that object file), so we disable it.
+        // (*) Native libs, and `#[compiler_builtins]` and `#[no_builtins]` crates are not glued,
+        // and we assume that they cannot define weak lang items. This is not currently enforced
+        // by the compiler, but that's ok because all this stuff is unstable anyway.
         let target = &tcx.sess.target;
-        if !target.is_like_msvc {
-            let missing_weak_lang_items: FxHashSet<&Symbol> = info
+        if !are_upstream_rust_objects_already_included(tcx.sess) {
+            let missing_weak_lang_items: FxHashSet<Symbol> = info
                 .used_crates
                 .iter()
-                .flat_map(|cnum| {
-                    tcx.missing_lang_items(*cnum)
-                        .iter()
-                        .filter(|l| lang_items::required(tcx, **l))
-                        .filter_map(|item| WEAK_ITEMS_SYMBOLS.get(item))
+                .flat_map(|&cnum| tcx.missing_lang_items(cnum))
+                .filter(|l| l.is_weak())
+                .filter_map(|&l| {
+                    let name = l.link_name()?;
+                    lang_items::required(tcx, l).then_some(name)
                 })
                 .collect();
             let prefix = if target.is_like_windows && target.arch == "x86" { "_" } else { "" };
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index 8ca1a6084cf..71f9179d02c 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -1,7 +1,6 @@
 #![allow(non_camel_case_types)]
 
 use rustc_errors::struct_span_err;
-use rustc_hir as hir;
 use rustc_hir::LangItem;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
@@ -140,7 +139,7 @@ pub fn build_unchecked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     lhs: Bx::Value,
     rhs: Bx::Value,
 ) -> Bx::Value {
-    let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shl, lhs, rhs);
+    let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
     // #1877, #10183: Ensure that input is always valid
     let rhs = shift_mask_rhs(bx, rhs);
     bx.shl(lhs, rhs)
@@ -152,7 +151,7 @@ pub fn build_unchecked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     lhs: Bx::Value,
     rhs: Bx::Value,
 ) -> Bx::Value {
-    let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shr, lhs, rhs);
+    let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
     // #1877, #10183: Ensure that input is always valid
     let rhs = shift_mask_rhs(bx, rhs);
     let is_signed = lhs_t.is_signed();
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 135ed680da2..e05646e1e86 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -666,10 +666,8 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
                     hcx.while_hashing_spans(false, |hcx| {
                         ct.to_valtree().hash_stable(hcx, &mut hasher)
                     });
-                    // Note: Don't use `StableHashResult` impl of `u64` here directly, since that
-                    // would lead to endianness problems.
-                    let hash: u128 = hasher.finish();
-                    (hash.to_le() as u64).to_le()
+                    let hash: u64 = hasher.finish();
+                    hash
                 });
 
                 if cpp_like_debuginfo(tcx) {
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 0ffe8872022..ebb531f1c43 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -13,43 +13,43 @@ use std::path::{Path, PathBuf};
 use std::process::ExitStatus;
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::lib_def_write_failure)]
+#[diag(codegen_ssa_lib_def_write_failure)]
 pub struct LibDefWriteFailure {
     pub error: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::version_script_write_failure)]
+#[diag(codegen_ssa_version_script_write_failure)]
 pub struct VersionScriptWriteFailure {
     pub error: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::symbol_file_write_failure)]
+#[diag(codegen_ssa_symbol_file_write_failure)]
 pub struct SymbolFileWriteFailure {
     pub error: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::ld64_unimplemented_modifier)]
+#[diag(codegen_ssa_ld64_unimplemented_modifier)]
 pub struct Ld64UnimplementedModifier;
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::linker_unsupported_modifier)]
+#[diag(codegen_ssa_linker_unsupported_modifier)]
 pub struct LinkerUnsupportedModifier;
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::L4Bender_exporting_symbols_unimplemented)]
+#[diag(codegen_ssa_L4Bender_exporting_symbols_unimplemented)]
 pub struct L4BenderExportingSymbolsUnimplemented;
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::no_natvis_directory)]
+#[diag(codegen_ssa_no_natvis_directory)]
 pub struct NoNatvisDirectory {
     pub error: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::copy_path_buf)]
+#[diag(codegen_ssa_copy_path_buf)]
 pub struct CopyPathBuf {
     pub source_file: PathBuf,
     pub output_path: PathBuf,
@@ -58,7 +58,7 @@ pub struct CopyPathBuf {
 
 // Reports Paths using `Debug` implementation rather than Path's `Display` implementation.
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::copy_path)]
+#[diag(codegen_ssa_copy_path)]
 pub struct CopyPath<'a> {
     from: DebugArgPath<'a>,
     to: DebugArgPath<'a>,
@@ -80,36 +80,36 @@ impl IntoDiagnosticArg for DebugArgPath<'_> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::ignoring_emit_path)]
+#[diag(codegen_ssa_ignoring_emit_path)]
 pub struct IgnoringEmitPath {
     pub extension: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::ignoring_output)]
+#[diag(codegen_ssa_ignoring_output)]
 pub struct IgnoringOutput {
     pub extension: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::create_temp_dir)]
+#[diag(codegen_ssa_create_temp_dir)]
 pub struct CreateTempDir {
     pub error: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::incompatible_linking_modifiers)]
+#[diag(codegen_ssa_incompatible_linking_modifiers)]
 pub struct IncompatibleLinkingModifiers;
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::add_native_library)]
+#[diag(codegen_ssa_add_native_library)]
 pub struct AddNativeLibrary {
     pub library_path: PathBuf,
     pub error: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::multiple_external_func_decl)]
+#[diag(codegen_ssa_multiple_external_func_decl)]
 pub struct MultipleExternalFuncDecl<'a> {
     #[primary_span]
     pub span: Span,
@@ -119,14 +119,17 @@ pub struct MultipleExternalFuncDecl<'a> {
 
 #[derive(Diagnostic)]
 pub enum LinkRlibError {
-    #[diag(codegen_ssa::rlib_missing_format)]
+    #[diag(codegen_ssa_rlib_missing_format)]
     MissingFormat,
 
-    #[diag(codegen_ssa::rlib_only_rmeta_found)]
+    #[diag(codegen_ssa_rlib_only_rmeta_found)]
     OnlyRmetaFound { crate_name: Symbol },
 
-    #[diag(codegen_ssa::rlib_not_found)]
+    #[diag(codegen_ssa_rlib_not_found)]
     NotFound { crate_name: Symbol },
+
+    #[diag(codegen_ssa_rlib_incompatible_dependency_formats)]
+    IncompatibleDependencyFormats { ty1: String, ty2: String, list1: String, list2: String },
 }
 
 pub struct ThorinErrorWrapper(pub thorin::Error);
@@ -136,188 +139,188 @@ impl IntoDiagnostic<'_> for ThorinErrorWrapper {
         let mut diag;
         match self.0 {
             thorin::Error::ReadInput(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_read_input_failure);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_read_input_failure);
                 diag
             }
             thorin::Error::ParseFileKind(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_file_kind);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_file_kind);
                 diag
             }
             thorin::Error::ParseObjectFile(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_object_file);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_object_file);
                 diag
             }
             thorin::Error::ParseArchiveFile(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_archive_file);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_archive_file);
                 diag
             }
             thorin::Error::ParseArchiveMember(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_archive_member);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_archive_member);
                 diag
             }
             thorin::Error::InvalidInputKind => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_invalid_input_kind);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_invalid_input_kind);
                 diag
             }
             thorin::Error::DecompressData(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_decompress_data);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_decompress_data);
                 diag
             }
             thorin::Error::NamelessSection(_, offset) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_section_without_name);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_section_without_name);
                 diag.set_arg("offset", format!("0x{:08x}", offset));
                 diag
             }
             thorin::Error::RelocationWithInvalidSymbol(section, offset) => {
                 diag =
-                    handler.struct_err(fluent::codegen_ssa::thorin_relocation_with_invalid_symbol);
+                    handler.struct_err(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol);
                 diag.set_arg("section", section);
                 diag.set_arg("offset", format!("0x{:08x}", offset));
                 diag
             }
             thorin::Error::MultipleRelocations(section, offset) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_relocations);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_relocations);
                 diag.set_arg("section", section);
                 diag.set_arg("offset", format!("0x{:08x}", offset));
                 diag
             }
             thorin::Error::UnsupportedRelocation(section, offset) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_unsupported_relocation);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_unsupported_relocation);
                 diag.set_arg("section", section);
                 diag.set_arg("offset", format!("0x{:08x}", offset));
                 diag
             }
             thorin::Error::MissingDwoName(id) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_dwo_name);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_dwo_name);
                 diag.set_arg("id", format!("0x{:08x}", id));
                 diag
             }
             thorin::Error::NoCompilationUnits => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_no_compilation_units);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_no_compilation_units);
                 diag
             }
             thorin::Error::NoDie => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_no_die);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_no_die);
                 diag
             }
             thorin::Error::TopLevelDieNotUnit => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_top_level_die_not_unit);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_top_level_die_not_unit);
                 diag
             }
             thorin::Error::MissingRequiredSection(section) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_required_section);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_required_section);
                 diag.set_arg("section", section);
                 diag
             }
             thorin::Error::ParseUnitAbbreviations(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_abbreviations);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_abbreviations);
                 diag
             }
             thorin::Error::ParseUnitAttribute(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_attribute);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_attribute);
                 diag
             }
             thorin::Error::ParseUnitHeader(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_header);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_header);
                 diag
             }
             thorin::Error::ParseUnit(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit);
                 diag
             }
             thorin::Error::IncompatibleIndexVersion(section, format, actual) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_incompatible_index_version);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_incompatible_index_version);
                 diag.set_arg("section", section);
                 diag.set_arg("actual", actual);
                 diag.set_arg("format", format);
                 diag
             }
             thorin::Error::OffsetAtIndex(_, index) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_offset_at_index);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_offset_at_index);
                 diag.set_arg("index", index);
                 diag
             }
             thorin::Error::StrAtOffset(_, offset) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_str_at_offset);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_str_at_offset);
                 diag.set_arg("offset", format!("0x{:08x}", offset));
                 diag
             }
             thorin::Error::ParseIndex(_, section) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_index);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_index);
                 diag.set_arg("section", section);
                 diag
             }
             thorin::Error::UnitNotInIndex(unit) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_unit_not_in_index);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_unit_not_in_index);
                 diag.set_arg("unit", format!("0x{:08x}", unit));
                 diag
             }
             thorin::Error::RowNotInIndex(_, row) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_row_not_in_index);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_row_not_in_index);
                 diag.set_arg("row", row);
                 diag
             }
             thorin::Error::SectionNotInRow => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_section_not_in_row);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_section_not_in_row);
                 diag
             }
             thorin::Error::EmptyUnit(unit) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_empty_unit);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_empty_unit);
                 diag.set_arg("unit", format!("0x{:08x}", unit));
                 diag
             }
             thorin::Error::MultipleDebugInfoSection => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_debug_info_section);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_debug_info_section);
                 diag
             }
             thorin::Error::MultipleDebugTypesSection => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_debug_types_section);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_debug_types_section);
                 diag
             }
             thorin::Error::NotSplitUnit => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_not_split_unit);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_not_split_unit);
                 diag
             }
             thorin::Error::DuplicateUnit(unit) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_duplicate_unit);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_duplicate_unit);
                 diag.set_arg("unit", format!("0x{:08x}", unit));
                 diag
             }
             thorin::Error::MissingReferencedUnit(unit) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_referenced_unit);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_referenced_unit);
                 diag.set_arg("unit", format!("0x{:08x}", unit));
                 diag
             }
             thorin::Error::NoOutputObjectCreated => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_not_output_object_created);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_not_output_object_created);
                 diag
             }
             thorin::Error::MixedInputEncodings => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_mixed_input_encodings);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_mixed_input_encodings);
                 diag
             }
             thorin::Error::Io(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_io);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_io);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
             thorin::Error::ObjectRead(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_object_read);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_object_read);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
             thorin::Error::ObjectWrite(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_object_write);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_object_write);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
             thorin::Error::GimliRead(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_gimli_read);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_gimli_read);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
             thorin::Error::GimliWrite(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_gimli_write);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_gimli_write);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
@@ -335,7 +338,7 @@ pub struct LinkingFailed<'a> {
 
 impl IntoDiagnostic<'_> for LinkingFailed<'_> {
     fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::codegen_ssa::linking_failed);
+        let mut diag = handler.struct_err(fluent::codegen_ssa_linking_failed);
         diag.set_arg("linker_path", format!("{}", self.linker_path.display()));
         diag.set_arg("exit_status", format!("{}", self.exit_status));
 
@@ -344,9 +347,9 @@ impl IntoDiagnostic<'_> for LinkingFailed<'_> {
         // Trying to match an error from OS linkers
         // which by now we have no way to translate.
         if self.escaped_output.contains("undefined reference to") {
-            diag.note(fluent::codegen_ssa::extern_funcs_not_found)
-                .note(fluent::codegen_ssa::specify_libraries_to_link)
-                .note(fluent::codegen_ssa::use_cargo_directive);
+            diag.note(fluent::codegen_ssa_extern_funcs_not_found)
+                .note(fluent::codegen_ssa_specify_libraries_to_link)
+                .note(fluent::codegen_ssa_use_cargo_directive);
         }
         diag
     }
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index bd4f0cac7eb..0802067cde6 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -17,6 +17,7 @@ use rustc_middle::mir::{self, AssertKind, SwitchTargets};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Instance, Ty, TypeVisitable};
+use rustc_session::config::OptLevel;
 use rustc_span::source_map::Span;
 use rustc_span::{sym, Symbol};
 use rustc_symbol_mangling::typeid::typeid_for_fnabi;
@@ -63,7 +64,9 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
         }
     }
 
-    fn lltarget<Bx: BuilderMethods<'a, 'tcx>>(
+    /// Get a basic block (creating it if necessary), possibly with a landing
+    /// pad next to it.
+    fn llbb_with_landing_pad<Bx: BuilderMethods<'a, 'tcx>>(
         &self,
         fx: &mut FunctionCx<'a, 'tcx, Bx>,
         target: mir::BasicBlock,
@@ -73,32 +76,36 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
         let target_funclet = fx.cleanup_kinds[target].funclet_bb(target);
         match (self.funclet_bb, target_funclet) {
             (None, None) => (lltarget, false),
-            (Some(f), Some(t_f)) if f == t_f || !base::wants_msvc_seh(fx.cx.tcx().sess) => {
-                (lltarget, false)
-            }
             // jump *into* cleanup - need a landing pad if GNU, cleanup pad if MSVC
             (None, Some(_)) => (fx.landing_pad_for(target), false),
             (Some(_), None) => span_bug!(span, "{:?} - jump out of cleanup?", self.terminator),
-            (Some(_), Some(_)) => (fx.landing_pad_for(target), true),
+            (Some(f), Some(t_f)) => {
+                if f == t_f || !base::wants_msvc_seh(fx.cx.tcx().sess) {
+                    (lltarget, false)
+                } else {
+                    (fx.landing_pad_for(target), true)
+                }
+            }
         }
     }
 
-    /// Create a basic block.
-    fn llblock<Bx: BuilderMethods<'a, 'tcx>>(
+    /// Get a basic block (creating it if necessary), possibly with cleanup
+    /// stuff in it or next to it.
+    fn llbb_with_cleanup<Bx: BuilderMethods<'a, 'tcx>>(
         &self,
         fx: &mut FunctionCx<'a, 'tcx, Bx>,
         target: mir::BasicBlock,
     ) -> Bx::BasicBlock {
-        let (lltarget, is_cleanupret) = self.lltarget(fx, target);
+        let (lltarget, is_cleanupret) = self.llbb_with_landing_pad(fx, target);
         if is_cleanupret {
             // MSVC cross-funclet jump - need a trampoline
-
-            debug!("llblock: creating cleanup trampoline for {:?}", target);
+            debug_assert!(base::wants_msvc_seh(fx.cx.tcx().sess));
+            debug!("llbb_with_cleanup: creating cleanup trampoline for {:?}", target);
             let name = &format!("{:?}_cleanup_trampoline_{:?}", self.bb, target);
-            let trampoline = Bx::append_block(fx.cx, fx.llfn, name);
-            let mut trampoline_bx = Bx::build(fx.cx, trampoline);
+            let trampoline_llbb = Bx::append_block(fx.cx, fx.llfn, name);
+            let mut trampoline_bx = Bx::build(fx.cx, trampoline_llbb);
             trampoline_bx.cleanup_ret(self.funclet(fx).unwrap(), Some(lltarget));
-            trampoline
+            trampoline_llbb
         } else {
             lltarget
         }
@@ -110,10 +117,11 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
         bx: &mut Bx,
         target: mir::BasicBlock,
     ) {
-        let (lltarget, is_cleanupret) = self.lltarget(fx, target);
+        let (lltarget, is_cleanupret) = self.llbb_with_landing_pad(fx, target);
         if is_cleanupret {
-            // micro-optimization: generate a `ret` rather than a jump
+            // MSVC micro-optimization: generate a `ret` rather than a jump
             // to a trampoline.
+            debug_assert!(base::wants_msvc_seh(fx.cx.tcx().sess));
             bx.cleanup_ret(self.funclet(fx).unwrap(), Some(lltarget));
         } else {
             bx.br(lltarget);
@@ -138,7 +146,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
         let fn_ty = bx.fn_decl_backend_type(&fn_abi);
 
         let unwind_block = if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) {
-            Some(self.llblock(fx, cleanup))
+            Some(self.llbb_with_cleanup(fx, cleanup))
         } else if fx.mir[self.bb].is_cleanup
             && fn_abi.can_unwind
             && !base::wants_msvc_seh(fx.cx.tcx().sess)
@@ -231,7 +239,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
                 options,
                 line_spans,
                 instance,
-                Some((ret_llbb, self.llblock(fx, cleanup), self.funclet(fx))),
+                Some((ret_llbb, self.llbb_with_cleanup(fx, cleanup), self.funclet(fx))),
             );
         } else {
             bx.codegen_inline_asm(template, &operands, options, line_spans, instance, None);
@@ -279,12 +287,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         assert_eq!(discr.layout.ty, switch_ty);
         let mut target_iter = targets.iter();
         if target_iter.len() == 1 {
-            // If there are two targets (one conditional, one fallback), emit br instead of switch
+            // If there are two targets (one conditional, one fallback), emit `br` instead of
+            // `switch`.
             let (test_value, target) = target_iter.next().unwrap();
-            let lltrue = helper.llblock(self, target);
-            let llfalse = helper.llblock(self, targets.otherwise());
+            let lltrue = helper.llbb_with_cleanup(self, target);
+            let llfalse = helper.llbb_with_cleanup(self, targets.otherwise());
             if switch_ty == bx.tcx().types.bool {
-                // Don't generate trivial icmps when switching on bool
+                // Don't generate trivial icmps when switching on bool.
                 match test_value {
                     0 => bx.cond_br(discr.immediate(), llfalse, lltrue),
                     1 => bx.cond_br(discr.immediate(), lltrue, llfalse),
@@ -296,11 +305,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval);
                 bx.cond_br(cmp, lltrue, llfalse);
             }
+        } else if self.cx.sess().opts.optimize == OptLevel::No
+            && target_iter.len() == 2
+            && self.mir[targets.otherwise()].is_empty_unreachable()
+        {
+            // In unoptimized builds, if there are two normal targets and the `otherwise` target is
+            // an unreachable BB, emit `br` instead of `switch`. This leaves behind the unreachable
+            // BB, which will usually (but not always) be dead code.
+            //
+            // Why only in unoptimized builds?
+            // - In unoptimized builds LLVM uses FastISel which does not support switches, so it
+            //   must fall back to the to the slower SelectionDAG isel. Therefore, using `br` gives
+            //   significant compile time speedups for unoptimized builds.
+            // - In optimized builds the above doesn't hold, and using `br` sometimes results in
+            //   worse generated code because LLVM can no longer tell that the value being switched
+            //   on can only have two values, e.g. 0 and 1.
+            //
+            let (test_value1, target1) = target_iter.next().unwrap();
+            let (_test_value2, target2) = target_iter.next().unwrap();
+            let ll1 = helper.llbb_with_cleanup(self, target1);
+            let ll2 = helper.llbb_with_cleanup(self, target2);
+            let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty));
+            let llval = bx.const_uint_big(switch_llty, test_value1);
+            let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval);
+            bx.cond_br(cmp, ll1, ll2);
         } else {
             bx.switch(
                 discr.immediate(),
-                helper.llblock(self, targets.otherwise()),
-                target_iter.map(|(value, target)| (value, helper.llblock(self, target))),
+                helper.llbb_with_cleanup(self, targets.otherwise()),
+                target_iter.map(|(value, target)| (value, helper.llbb_with_cleanup(self, target))),
             );
         }
     }
@@ -530,7 +563,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let cond = bx.expect(cond, expected);
 
         // Create the failure block and the conditional branch to it.
-        let lltarget = helper.llblock(self, target);
+        let lltarget = helper.llbb_with_cleanup(self, target);
         let panic_block = bx.append_sibling_block("panic");
         if expected {
             bx.cond_br(cond, lltarget, panic_block);
@@ -1459,20 +1492,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 //          bar();
                 //      }
                 Some(&mir::TerminatorKind::Abort) => {
-                    let cs_bb =
+                    let cs_llbb =
                         Bx::append_block(self.cx, self.llfn, &format!("cs_funclet{:?}", bb));
-                    let cp_bb =
+                    let cp_llbb =
                         Bx::append_block(self.cx, self.llfn, &format!("cp_funclet{:?}", bb));
-                    ret_llbb = cs_bb;
+                    ret_llbb = cs_llbb;
 
-                    let mut cs_bx = Bx::build(self.cx, cs_bb);
-                    let cs = cs_bx.catch_switch(None, None, &[cp_bb]);
+                    let mut cs_bx = Bx::build(self.cx, cs_llbb);
+                    let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
 
                     // The "null" here is actually a RTTI type descriptor for the
                     // C++ personality function, but `catch (...)` has no type so
                     // it's null. The 64 here is actually a bitfield which
                     // represents that this is a catch-all block.
-                    let mut cp_bx = Bx::build(self.cx, cp_bb);
+                    let mut cp_bx = Bx::build(self.cx, cp_llbb);
                     let null = cp_bx.const_null(
                         cp_bx.type_i8p_ext(cp_bx.cx().data_layout().instruction_address_space),
                     );
@@ -1481,10 +1514,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     cp_bx.br(llbb);
                 }
                 _ => {
-                    let cleanup_bb =
+                    let cleanup_llbb =
                         Bx::append_block(self.cx, self.llfn, &format!("funclet_{:?}", bb));
-                    ret_llbb = cleanup_bb;
-                    let mut cleanup_bx = Bx::build(self.cx, cleanup_bb);
+                    ret_llbb = cleanup_llbb;
+                    let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
                     funclet = cleanup_bx.cleanup_pad(None, &[]);
                     cleanup_bx.br(llbb);
                 }
@@ -1492,19 +1525,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             self.funclets[bb] = Some(funclet);
             ret_llbb
         } else {
-            let bb = Bx::append_block(self.cx, self.llfn, "cleanup");
-            let mut bx = Bx::build(self.cx, bb);
+            let cleanup_llbb = Bx::append_block(self.cx, self.llfn, "cleanup");
+            let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
 
             let llpersonality = self.cx.eh_personality();
             let llretty = self.landing_pad_type();
-            let lp = bx.cleanup_landing_pad(llretty, llpersonality);
+            let lp = cleanup_bx.cleanup_landing_pad(llretty, llpersonality);
 
-            let slot = self.get_personality_slot(&mut bx);
-            slot.storage_live(&mut bx);
-            Pair(bx.extract_value(lp, 0), bx.extract_value(lp, 1)).store(&mut bx, slot);
+            let slot = self.get_personality_slot(&mut cleanup_bx);
+            slot.storage_live(&mut cleanup_bx);
+            Pair(cleanup_bx.extract_value(lp, 0), cleanup_bx.extract_value(lp, 1))
+                .store(&mut cleanup_bx, slot);
 
-            bx.br(llbb);
-            bx.llbb()
+            cleanup_bx.br(llbb);
+            cleanup_llbb
         }
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 2b931bfc91d..da9aaf00ecf 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -148,10 +148,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     let debug_context = cx.create_function_debug_context(instance, &fn_abi, llfn, &mir);
 
     let start_llbb = Bx::append_block(cx, llfn, "start");
-    let mut bx = Bx::build(cx, start_llbb);
+    let mut start_bx = Bx::build(cx, start_llbb);
 
     if mir.basic_blocks.iter().any(|bb| bb.is_cleanup) {
-        bx.set_personality_fn(cx.eh_personality());
+        start_bx.set_personality_fn(cx.eh_personality());
     }
 
     let cleanup_kinds = analyze::cleanup_kinds(&mir);
@@ -180,7 +180,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         caller_location: None,
     };
 
-    fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut bx);
+    fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);
 
     // Evaluate all required consts; codegen later assumes that CTFE will never fail.
     let mut all_consts_ok = true;
@@ -206,29 +206,29 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     // Allocate variable and temp allocas
     fx.locals = {
-        let args = arg_local_refs(&mut bx, &mut fx, &memory_locals);
+        let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals);
 
         let mut allocate_local = |local| {
             let decl = &mir.local_decls[local];
-            let layout = bx.layout_of(fx.monomorphize(decl.ty));
+            let layout = start_bx.layout_of(fx.monomorphize(decl.ty));
             assert!(!layout.ty.has_erasable_regions());
 
             if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() {
                 debug!("alloc: {:?} (return place) -> place", local);
-                let llretptr = bx.get_param(0);
+                let llretptr = start_bx.get_param(0);
                 return LocalRef::Place(PlaceRef::new_sized(llretptr, layout));
             }
 
             if memory_locals.contains(local) {
                 debug!("alloc: {:?} -> place", local);
                 if layout.is_unsized() {
-                    LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut bx, layout))
+                    LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut start_bx, layout))
                 } else {
-                    LocalRef::Place(PlaceRef::alloca(&mut bx, layout))
+                    LocalRef::Place(PlaceRef::alloca(&mut start_bx, layout))
                 }
             } else {
                 debug!("alloc: {:?} -> operand", local);
-                LocalRef::new_operand(&mut bx, layout)
+                LocalRef::new_operand(&mut start_bx, layout)
             }
         };
 
@@ -240,7 +240,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     };
 
     // Apply debuginfo to the newly allocated locals.
-    fx.debug_introduce_locals(&mut bx);
+    fx.debug_introduce_locals(&mut start_bx);
 
     // Codegen the body of each block using reverse postorder
     for (bb, _) in traversal::reverse_postorder(&mir) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 4ed99df1e81..4aab31fbfe7 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -4,7 +4,6 @@ use super::{FunctionCx, LocalRef};
 
 use crate::base;
 use crate::common::{self, IntPredicate};
-use crate::meth::get_vtable;
 use crate::traits::*;
 use crate::MemFlags;
 
@@ -14,7 +13,6 @@ use rustc_middle::ty::cast::{CastTy, IntTy};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
 use rustc_span::source_map::{Span, DUMMY_SP};
-use rustc_target::abi::Size;
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     #[instrument(level = "trace", skip(self, bx))]
@@ -274,27 +272,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         }
                     }
                     mir::CastKind::DynStar => {
-                        let data = match operand.val {
+                        let (lldata, llextra) = match operand.val {
                             OperandValue::Ref(_, _, _) => todo!(),
-                            OperandValue::Immediate(v) => v,
-                            OperandValue::Pair(_, _) => todo!(),
-                        };
-                        let trait_ref =
-                            if let ty::Dynamic(data, _, ty::DynStar) = cast.ty.kind() {
-                                data.principal()
-                            } else {
-                                bug!("Only valid to do a DynStar cast into a DynStar type")
-                            };
-                        let vtable = get_vtable(bx.cx(), source.ty(self.mir, bx.tcx()), trait_ref);
-                        let vtable = bx.pointercast(vtable, bx.cx().type_ptr_to(bx.cx().type_isize()));
-                        // FIXME(dyn-star): this is probably not the best way to check if this is
-                        // a pointer, and really we should ensure that the value is a suitable
-                        // pointer earlier in the compilation process.
-                        let data = match operand.layout.pointee_info_at(bx.cx(), Size::ZERO) {
-                            Some(_) => bx.ptrtoint(data, bx.cx().type_isize()),
-                            None => data,
+                            OperandValue::Immediate(v) => (v, None),
+                            OperandValue::Pair(v, l) => (v, Some(l)),
                         };
-                        OperandValue::Pair(data, vtable)
+                        let (lldata, llextra) =
+                            base::cast_to_dyn_star(&mut bx, lldata, operand.layout, cast.ty, llextra);
+                        OperandValue::Pair(lldata, llextra)
                     }
                     mir::CastKind::Pointer(
                         PointerCast::MutToConstPointer | PointerCast::ArrayToPointer,
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 0e259bcd1a4..a4368303de5 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -13,17 +13,25 @@ pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
 // if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted
 
 const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    // tidy-alphabetical-start
     ("aclass", Some(sym::arm_target_feature)),
-    ("mclass", Some(sym::arm_target_feature)),
-    ("rclass", Some(sym::arm_target_feature)),
-    ("dsp", Some(sym::arm_target_feature)),
-    ("neon", Some(sym::arm_target_feature)),
+    ("aes", Some(sym::arm_target_feature)),
     ("crc", Some(sym::arm_target_feature)),
     ("crypto", Some(sym::arm_target_feature)),
-    ("aes", Some(sym::arm_target_feature)),
-    ("sha2", Some(sym::arm_target_feature)),
-    ("i8mm", Some(sym::arm_target_feature)),
+    ("d32", Some(sym::arm_target_feature)),
     ("dotprod", Some(sym::arm_target_feature)),
+    ("dsp", Some(sym::arm_target_feature)),
+    ("fp-armv8", Some(sym::arm_target_feature)),
+    ("i8mm", Some(sym::arm_target_feature)),
+    ("mclass", Some(sym::arm_target_feature)),
+    ("neon", Some(sym::arm_target_feature)),
+    ("rclass", Some(sym::arm_target_feature)),
+    ("sha2", Some(sym::arm_target_feature)),
+    // This is needed for inline assembly, but shouldn't be stabilized as-is
+    // since it should be enabled per-function using #[instruction_set], not
+    // #[target_feature].
+    ("thumb-mode", Some(sym::arm_target_feature)),
+    ("thumb2", Some(sym::arm_target_feature)),
     ("v5te", Some(sym::arm_target_feature)),
     ("v6", Some(sym::arm_target_feature)),
     ("v6k", Some(sym::arm_target_feature)),
@@ -33,104 +41,97 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("vfp2", Some(sym::arm_target_feature)),
     ("vfp3", Some(sym::arm_target_feature)),
     ("vfp4", Some(sym::arm_target_feature)),
-    ("fp-armv8", Some(sym::arm_target_feature)),
-    // This is needed for inline assembly, but shouldn't be stabilized as-is
-    // since it should be enabled per-function using #[instruction_set], not
-    // #[target_feature].
-    ("thumb-mode", Some(sym::arm_target_feature)),
-    ("thumb2", Some(sym::arm_target_feature)),
-    ("d32", Some(sym::arm_target_feature)),
+    // tidy-alphabetical-end
 ];
 
 const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    // FEAT_AdvSimd & FEAT_FP
-    ("neon", None),
-    // FEAT_FP16
-    ("fp16", None),
-    // FEAT_SVE
-    ("sve", None),
+    // tidy-alphabetical-start
+    // FEAT_AES
+    ("aes", None),
+    // FEAT_BF16
+    ("bf16", None),
+    // FEAT_BTI
+    ("bti", None),
     // FEAT_CRC
     ("crc", None),
-    // FEAT_RAS
-    ("ras", None),
-    // FEAT_LSE
-    ("lse", None),
-    // FEAT_RDM
-    ("rdm", None),
-    // FEAT_RCPC
-    ("rcpc", None),
-    // FEAT_RCPC2
-    ("rcpc2", None),
-    // FEAT_DotProd
-    ("dotprod", None),
-    // FEAT_TME
-    ("tme", None),
-    // FEAT_FHM
-    ("fhm", None),
     // FEAT_DIT
     ("dit", None),
-    // FEAT_FLAGM
-    ("flagm", None),
-    // FEAT_SSBS
-    ("ssbs", None),
-    // FEAT_SB
-    ("sb", None),
-    // FEAT_PAUTH (address authentication)
-    ("paca", None),
-    // FEAT_PAUTH (generic authentication)
-    ("pacg", None),
+    // FEAT_DotProd
+    ("dotprod", None),
     // FEAT_DPB
     ("dpb", None),
     // FEAT_DPB2
     ("dpb2", None),
-    // FEAT_SVE2
-    ("sve2", None),
-    // FEAT_SVE2_AES
-    ("sve2-aes", None),
-    // FEAT_SVE2_SM4
-    ("sve2-sm4", None),
-    // FEAT_SVE2_SHA3
-    ("sve2-sha3", None),
-    // FEAT_SVE2_BitPerm
-    ("sve2-bitperm", None),
-    // FEAT_FRINTTS
-    ("frintts", None),
-    // FEAT_I8MM
-    ("i8mm", None),
     // FEAT_F32MM
     ("f32mm", None),
     // FEAT_F64MM
     ("f64mm", None),
-    // FEAT_BF16
-    ("bf16", None),
-    // FEAT_RAND
-    ("rand", None),
-    // FEAT_BTI
-    ("bti", None),
-    // FEAT_MTE
-    ("mte", None),
-    // FEAT_JSCVT
-    ("jsconv", None),
     // FEAT_FCMA
     ("fcma", None),
-    // FEAT_AES
-    ("aes", None),
+    // FEAT_FHM
+    ("fhm", None),
+    // FEAT_FLAGM
+    ("flagm", None),
+    // FEAT_FP16
+    ("fp16", None),
+    // FEAT_FRINTTS
+    ("frintts", None),
+    // FEAT_I8MM
+    ("i8mm", None),
+    // FEAT_JSCVT
+    ("jsconv", None),
+    // FEAT_LOR
+    ("lor", None),
+    // FEAT_LSE
+    ("lse", None),
+    // FEAT_MTE
+    ("mte", None),
+    // FEAT_AdvSimd & FEAT_FP
+    ("neon", None),
+    // FEAT_PAUTH (address authentication)
+    ("paca", None),
+    // FEAT_PAUTH (generic authentication)
+    ("pacg", None),
+    // FEAT_PAN
+    ("pan", None),
+    // FEAT_PMUv3
+    ("pmuv3", None),
+    // FEAT_RAND
+    ("rand", None),
+    // FEAT_RAS
+    ("ras", None),
+    // FEAT_RCPC
+    ("rcpc", None),
+    // FEAT_RCPC2
+    ("rcpc2", None),
+    // FEAT_RDM
+    ("rdm", None),
+    // FEAT_SB
+    ("sb", None),
     // FEAT_SHA1 & FEAT_SHA256
     ("sha2", None),
     // FEAT_SHA512 & FEAT_SHA3
     ("sha3", None),
     // FEAT_SM3 & FEAT_SM4
     ("sm4", None),
-    // FEAT_PAN
-    ("pan", None),
-    // FEAT_LOR
-    ("lor", None),
-    // FEAT_VHE
-    ("vh", None),
-    // FEAT_PMUv3
-    ("pmuv3", None),
     // FEAT_SPE
     ("spe", None),
+    // FEAT_SSBS
+    ("ssbs", None),
+    // FEAT_SVE
+    ("sve", None),
+    // FEAT_SVE2
+    ("sve2", None),
+    // FEAT_SVE2_AES
+    ("sve2-aes", None),
+    // FEAT_SVE2_BitPerm
+    ("sve2-bitperm", None),
+    // FEAT_SVE2_SHA3
+    ("sve2-sha3", None),
+    // FEAT_SVE2_SM4
+    ("sve2-sm4", None),
+    // FEAT_TME
+    ("tme", None),
     ("v8.1a", Some(sym::aarch64_ver_target_feature)),
     ("v8.2a", Some(sym::aarch64_ver_target_feature)),
     ("v8.3a", Some(sym::aarch64_ver_target_feature)),
@@ -138,6 +139,9 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("v8.5a", Some(sym::aarch64_ver_target_feature)),
     ("v8.6a", Some(sym::aarch64_ver_target_feature)),
     ("v8.7a", Some(sym::aarch64_ver_target_feature)),
+    // FEAT_VHE
+    ("vh", None),
+    // tidy-alphabetical-end
 ];
 
 const AARCH64_TIED_FEATURES: &[&[&str]] = &[
@@ -145,6 +149,7 @@ const AARCH64_TIED_FEATURES: &[&[&str]] = &[
 ];
 
 const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    // tidy-alphabetical-start
     ("adx", None),
     ("aes", None),
     ("avx", None),
@@ -194,69 +199,81 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("xsavec", None),
     ("xsaveopt", None),
     ("xsaves", None),
+    // tidy-alphabetical-end
 ];
 
 const HEXAGON_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    // tidy-alphabetical-start
     ("hvx", Some(sym::hexagon_target_feature)),
     ("hvx-length128b", Some(sym::hexagon_target_feature)),
+    // tidy-alphabetical-end
 ];
 
 const POWERPC_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    // tidy-alphabetical-start
     ("altivec", Some(sym::powerpc_target_feature)),
     ("power8-altivec", Some(sym::powerpc_target_feature)),
-    ("power9-altivec", Some(sym::powerpc_target_feature)),
     ("power8-vector", Some(sym::powerpc_target_feature)),
+    ("power9-altivec", Some(sym::powerpc_target_feature)),
     ("power9-vector", Some(sym::powerpc_target_feature)),
     ("vsx", Some(sym::powerpc_target_feature)),
+    // tidy-alphabetical-end
 ];
 
 const MIPS_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    // tidy-alphabetical-start
     ("fp64", Some(sym::mips_target_feature)),
     ("msa", Some(sym::mips_target_feature)),
     ("virt", Some(sym::mips_target_feature)),
+    // tidy-alphabetical-end
 ];
 
 const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("m", Some(sym::riscv_target_feature)),
+    // tidy-alphabetical-start
     ("a", Some(sym::riscv_target_feature)),
     ("c", Some(sym::riscv_target_feature)),
-    ("f", Some(sym::riscv_target_feature)),
     ("d", Some(sym::riscv_target_feature)),
     ("e", Some(sym::riscv_target_feature)),
+    ("f", Some(sym::riscv_target_feature)),
+    ("m", Some(sym::riscv_target_feature)),
     ("v", Some(sym::riscv_target_feature)),
-    ("zfinx", Some(sym::riscv_target_feature)),
-    ("zdinx", Some(sym::riscv_target_feature)),
-    ("zhinx", Some(sym::riscv_target_feature)),
-    ("zhinxmin", Some(sym::riscv_target_feature)),
-    ("zfh", Some(sym::riscv_target_feature)),
-    ("zfhmin", Some(sym::riscv_target_feature)),
     ("zba", Some(sym::riscv_target_feature)),
     ("zbb", Some(sym::riscv_target_feature)),
     ("zbc", Some(sym::riscv_target_feature)),
-    ("zbs", Some(sym::riscv_target_feature)),
     ("zbkb", Some(sym::riscv_target_feature)),
     ("zbkc", Some(sym::riscv_target_feature)),
     ("zbkx", Some(sym::riscv_target_feature)),
+    ("zbs", Some(sym::riscv_target_feature)),
+    ("zdinx", Some(sym::riscv_target_feature)),
+    ("zfh", Some(sym::riscv_target_feature)),
+    ("zfhmin", Some(sym::riscv_target_feature)),
+    ("zfinx", Some(sym::riscv_target_feature)),
+    ("zhinx", Some(sym::riscv_target_feature)),
+    ("zhinxmin", Some(sym::riscv_target_feature)),
+    ("zk", Some(sym::riscv_target_feature)),
+    ("zkn", Some(sym::riscv_target_feature)),
     ("zknd", Some(sym::riscv_target_feature)),
     ("zkne", Some(sym::riscv_target_feature)),
     ("zknh", Some(sym::riscv_target_feature)),
-    ("zksed", Some(sym::riscv_target_feature)),
-    ("zksh", Some(sym::riscv_target_feature)),
     ("zkr", Some(sym::riscv_target_feature)),
-    ("zkn", Some(sym::riscv_target_feature)),
     ("zks", Some(sym::riscv_target_feature)),
-    ("zk", Some(sym::riscv_target_feature)),
+    ("zksed", Some(sym::riscv_target_feature)),
+    ("zksh", Some(sym::riscv_target_feature)),
     ("zkt", Some(sym::riscv_target_feature)),
+    // tidy-alphabetical-end
 ];
 
 const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("simd128", None),
+    // tidy-alphabetical-start
     ("atomics", Some(sym::wasm_target_feature)),
-    ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
     ("bulk-memory", Some(sym::wasm_target_feature)),
+    ("multivalue", Some(sym::wasm_target_feature)),
     ("mutable-globals", Some(sym::wasm_target_feature)),
+    ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
     ("reference-types", Some(sym::wasm_target_feature)),
     ("sign-ext", Some(sym::wasm_target_feature)),
+    ("simd128", None),
+    // tidy-alphabetical-end
 ];
 
 const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))];
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 87e347c61e2..5c35070ea66 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -119,7 +119,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
         tcx: TyCtxt<'tcx>,
         module_name: &str,
         kind: AllocatorKind,
-        has_alloc_error_handler: bool,
+        alloc_error_handler_kind: AllocatorKind,
     ) -> Self::Module;
     /// This generates the codegen unit and returns it along with
     /// a `u64` giving an estimate of the unit's processing cost.
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index 8158e8dd011..bdc6a91cf6a 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -5,7 +5,6 @@ use crate::common::TypeKind;
 use crate::mir::place::PlaceRef;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::DUMMY_SP;
 use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg};
 use rustc_target::abi::{AddressSpace, Integer};
 
@@ -75,16 +74,16 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
     }
 
     fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_sized(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all())
+        ty.is_sized(self.tcx(), ty::ParamEnv::reveal_all())
     }
 
     fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_freeze(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all())
+        ty.is_freeze(self.tcx(), ty::ParamEnv::reveal_all())
     }
 
     fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
         let param_env = ty::ParamEnv::reveal_all();
-        if ty.is_sized(self.tcx().at(DUMMY_SP), param_env) {
+        if ty.is_sized(self.tcx(), param_env) {
             return false;
         }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 136bfbeaad2..4977a5d6bbf 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -64,7 +64,7 @@ pub struct ConstEvalErr<'tcx> {
 impl<'tcx> ConstEvalErr<'tcx> {
     /// Turn an interpreter error into something to report to the user.
     /// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
-    /// Should be called only if the error is actually going to to be reported!
+    /// Should be called only if the error is actually going to be reported!
     pub fn new<'mir, M: Machine<'mir, 'tcx>>(
         ecx: &InterpCx<'mir, 'tcx, M>,
         error: InterpErrorInfo<'tcx>,
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 cdcebb61c2e..f1674d04f8d 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -25,10 +25,12 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
 /// 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 hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-    match tcx.hir().get(hir_id) {
-        hir::Node::Ctor(_) => hir::Constness::Const,
+    let def_id = def_id.expect_local();
+    let node = tcx.hir().get_by_def_id(def_id);
 
+    match node {
+        hir::Node::Ctor(_) => hir::Constness::Const,
+        hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness,
         hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
             // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
             // foreign items cannot be evaluated at compile-time.
@@ -39,62 +41,20 @@ fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
             };
             if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
         }
+        _ => {
+            if let Some(fn_kind) = node.fn_kind() {
+                if fn_kind.constness() == hir::Constness::Const {
+                    return hir::Constness::Const;
+                }
 
-        hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
-            if tcx.is_const_default_method(def_id) =>
-        {
-            hir::Constness::Const
-        }
-
-        hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. })
-        | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. })
-        | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. })
-        | hir::Node::AnonConst(_)
-        | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
-        | hir::Node::ImplItem(hir::ImplItem {
-            kind:
-                hir::ImplItemKind::Fn(
-                    hir::FnSig {
-                        header: hir::FnHeader { constness: hir::Constness::Const, .. },
-                        ..
-                    },
-                    ..,
-                ),
-            ..
-        }) => hir::Constness::Const,
-
-        hir::Node::ImplItem(hir::ImplItem {
-            kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..),
-            ..
-        }) => {
-            let parent_hir_id = tcx.hir().get_parent_node(hir_id);
-            match tcx.hir().get(parent_hir_id) {
-                hir::Node::Item(hir::Item {
-                    kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
-                    ..
-                }) => *constness,
-                _ => span_bug!(
-                    tcx.def_span(parent_hir_id.owner),
-                    "impl item's parent node is not an impl",
-                ),
+                // If the function itself is not annotated with `const`, it may still be a `const fn`
+                // if it resides in a const trait impl.
+                let is_const = is_parent_const_impl_raw(tcx, def_id);
+                if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
+            } else {
+                hir::Constness::NotConst
             }
         }
-
-        hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..),
-            ..
-        })
-        | hir::Node::TraitItem(hir::TraitItem {
-            kind:
-                hir::TraitItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..),
-            ..
-        })
-        | hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
-            ..
-        }) => *constness,
-
-        _ => hir::Constness::NotConst,
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index e5acacd9188..35d58d2f638 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -2,10 +2,10 @@ use rustc_hir::def::DefKind;
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use std::borrow::Borrow;
-use std::collections::hash_map::Entry;
 use std::hash::Hash;
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::IndexEntry;
 use std::fmt;
 
 use rustc_ast::Mutability;
@@ -107,18 +107,18 @@ impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
     }
 }
 
-impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
+impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> {
     #[inline(always)]
     fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
     where
         K: Borrow<Q>,
     {
-        FxHashMap::contains_key(self, k)
+        FxIndexMap::contains_key(self, k)
     }
 
     #[inline(always)]
     fn insert(&mut self, k: K, v: V) -> Option<V> {
-        FxHashMap::insert(self, k, v)
+        FxIndexMap::insert(self, k, v)
     }
 
     #[inline(always)]
@@ -126,7 +126,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
     where
         K: Borrow<Q>,
     {
-        FxHashMap::remove(self, k)
+        FxIndexMap::remove(self, k)
     }
 
     #[inline(always)]
@@ -148,8 +148,8 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
     #[inline(always)]
     fn get_mut_or<E>(&mut self, k: K, vacant: impl FnOnce() -> Result<V, E>) -> Result<&mut V, E> {
         match self.entry(k) {
-            Entry::Occupied(e) => Ok(e.into_mut()),
-            Entry::Vacant(e) => {
+            IndexEntry::Occupied(e) => Ok(e.into_mut()),
+            IndexEntry::Vacant(e) => {
                 let v = vacant()?;
                 Ok(e.insert(v))
             }
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index a964fe8465e..f4da1188395 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -212,7 +212,7 @@ fn create_pointee_place<'tcx>(
 ) -> MPlaceTy<'tcx> {
     let tcx = ecx.tcx.tcx;
 
-    if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty()) {
+    if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty()) {
         // We need to create `Allocation`s for custom DSTs
 
         let (unsized_inner_ty, num_elems) = get_info_on_unsized_field(ty, valtree, tcx);
@@ -398,7 +398,7 @@ fn valtree_into_mplace<'tcx>(
 
                 let mut place_inner = match ty.kind() {
                     ty::Str | ty::Slice(_) => ecx.mplace_index(&place, i as u64).unwrap(),
-                    _ if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty())
+                    _ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty())
                         && i == branches.len() - 1 =>
                     {
                         // Note: For custom DSTs we need to manually process the last unsized field.
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index c6cb7a8b961..4b055076742 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -3,18 +3,18 @@ use rustc_macros::Diagnostic;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unstable_in_stable)]
+#[diag(const_eval_unstable_in_stable)]
 pub(crate) struct UnstableInStable {
     pub gate: String,
     #[primary_span]
     pub span: Span,
     #[suggestion(
-        const_eval::unstable_sugg,
+        unstable_sugg,
         code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",
         applicability = "has-placeholders"
     )]
     #[suggestion(
-        const_eval::bypass_sugg,
+        bypass_sugg,
         code = "#[rustc_allow_const_fn_unstable({gate})]\n",
         applicability = "has-placeholders"
     )]
@@ -22,35 +22,35 @@ pub(crate) struct UnstableInStable {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::thread_local_access, code = "E0625")]
+#[diag(const_eval_thread_local_access, code = "E0625")]
 pub(crate) struct NonConstOpErr {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::static_access, code = "E0013")]
+#[diag(const_eval_static_access, code = "E0013")]
 #[help]
 pub(crate) struct StaticAccessErr {
     #[primary_span]
     pub span: Span,
     pub kind: ConstContext,
-    #[note(const_eval::teach_note)]
-    #[help(const_eval::teach_help)]
+    #[note(teach_note)]
+    #[help(teach_help)]
     pub teach: Option<()>,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::raw_ptr_to_int)]
+#[diag(const_eval_raw_ptr_to_int)]
 #[note]
-#[note(const_eval::note2)]
+#[note(note2)]
 pub(crate) struct RawPtrToIntErr {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::raw_ptr_comparison)]
+#[diag(const_eval_raw_ptr_comparison)]
 #[note]
 pub(crate) struct RawPtrComparisonErr {
     #[primary_span]
@@ -58,14 +58,14 @@ pub(crate) struct RawPtrComparisonErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::panic_non_str)]
+#[diag(const_eval_panic_non_str)]
 pub(crate) struct PanicNonStrErr {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::mut_deref, code = "E0658")]
+#[diag(const_eval_mut_deref, code = "E0658")]
 pub(crate) struct MutDerefErr {
     #[primary_span]
     pub span: Span,
@@ -73,7 +73,7 @@ pub(crate) struct MutDerefErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::transient_mut_borrow, code = "E0658")]
+#[diag(const_eval_transient_mut_borrow, code = "E0658")]
 pub(crate) struct TransientMutBorrowErr {
     #[primary_span]
     pub span: Span,
@@ -81,7 +81,7 @@ pub(crate) struct TransientMutBorrowErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::transient_mut_borrow_raw, code = "E0658")]
+#[diag(const_eval_transient_mut_borrow_raw, code = "E0658")]
 pub(crate) struct TransientMutBorrowErrRaw {
     #[primary_span]
     pub span: Span,
@@ -89,7 +89,7 @@ pub(crate) struct TransientMutBorrowErrRaw {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::max_num_nodes_in_const)]
+#[diag(const_eval_max_num_nodes_in_const)]
 pub(crate) struct MaxNumNodesInConstErr {
     #[primary_span]
     pub span: Span,
@@ -97,7 +97,7 @@ pub(crate) struct MaxNumNodesInConstErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unallowed_fn_pointer_call)]
+#[diag(const_eval_unallowed_fn_pointer_call)]
 pub(crate) struct UnallowedFnPointerCall {
     #[primary_span]
     pub span: Span,
@@ -105,7 +105,7 @@ pub(crate) struct UnallowedFnPointerCall {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unstable_const_fn)]
+#[diag(const_eval_unstable_const_fn)]
 pub(crate) struct UnstableConstFn {
     #[primary_span]
     pub span: Span,
@@ -113,26 +113,26 @@ pub(crate) struct UnstableConstFn {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unallowed_mutable_refs, code = "E0764")]
+#[diag(const_eval_unallowed_mutable_refs, code = "E0764")]
 pub(crate) struct UnallowedMutableRefs {
     #[primary_span]
     pub span: Span,
     pub kind: ConstContext,
-    #[note(const_eval::teach_note)]
+    #[note(teach_note)]
     pub teach: Option<()>,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unallowed_mutable_refs_raw, code = "E0764")]
+#[diag(const_eval_unallowed_mutable_refs_raw, code = "E0764")]
 pub(crate) struct UnallowedMutableRefsRaw {
     #[primary_span]
     pub span: Span,
     pub kind: ConstContext,
-    #[note(const_eval::teach_note)]
+    #[note(teach_note)]
     pub teach: Option<()>,
 }
 #[derive(Diagnostic)]
-#[diag(const_eval::non_const_fmt_macro_call, code = "E0015")]
+#[diag(const_eval_non_const_fmt_macro_call, code = "E0015")]
 pub(crate) struct NonConstFmtMacroCall {
     #[primary_span]
     pub span: Span,
@@ -140,7 +140,7 @@ pub(crate) struct NonConstFmtMacroCall {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::non_const_fn_call, code = "E0015")]
+#[diag(const_eval_non_const_fn_call, code = "E0015")]
 pub(crate) struct NonConstFnCall {
     #[primary_span]
     pub span: Span,
@@ -149,7 +149,7 @@ pub(crate) struct NonConstFnCall {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unallowed_op_in_const_context)]
+#[diag(const_eval_unallowed_op_in_const_context)]
 pub(crate) struct UnallowedOpInConstContext {
     #[primary_span]
     pub span: Span,
@@ -157,18 +157,18 @@ pub(crate) struct UnallowedOpInConstContext {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unallowed_heap_allocations, code = "E0010")]
+#[diag(const_eval_unallowed_heap_allocations, code = "E0010")]
 pub(crate) struct UnallowedHeapAllocations {
     #[primary_span]
     #[label]
     pub span: Span,
     pub kind: ConstContext,
-    #[note(const_eval::teach_note)]
+    #[note(teach_note)]
     pub teach: Option<()>,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unallowed_inline_asm, code = "E0015")]
+#[diag(const_eval_unallowed_inline_asm, code = "E0015")]
 pub(crate) struct UnallowedInlineAsm {
     #[primary_span]
     pub span: Span,
@@ -176,7 +176,7 @@ pub(crate) struct UnallowedInlineAsm {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::interior_mutable_data_refer, code = "E0492")]
+#[diag(const_eval_interior_mutable_data_refer, code = "E0492")]
 pub(crate) struct InteriorMutableDataRefer {
     #[primary_span]
     #[label]
@@ -184,12 +184,12 @@ pub(crate) struct InteriorMutableDataRefer {
     #[help]
     pub opt_help: Option<()>,
     pub kind: ConstContext,
-    #[note(const_eval::teach_note)]
+    #[note(teach_note)]
     pub teach: Option<()>,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::interior_mutability_borrow)]
+#[diag(const_eval_interior_mutability_borrow)]
 pub(crate) struct InteriorMutabilityBorrow {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 764224fd007..269ae15d497 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -42,10 +42,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?;
                 self.write_immediate(res, dest)?;
             }
-            // FIXME: We shouldn't use `misc_cast` for these but handle them separately.
-            IntToInt | FloatToInt | FloatToFloat | IntToFloat | FnPtrToPtr | PtrToPtr => {
+
+            IntToInt | IntToFloat => {
+                let src = self.read_immediate(src)?;
+                let res = self.int_to_int_or_float(&src, cast_ty)?;
+                self.write_immediate(res, dest)?;
+            }
+
+            FloatToFloat | FloatToInt => {
                 let src = self.read_immediate(src)?;
-                let res = self.misc_cast(&src, cast_ty)?;
+                let res = self.float_to_float_or_int(&src, cast_ty)?;
+                self.write_immediate(res, dest)?;
+            }
+
+            FnPtrToPtr | PtrToPtr => {
+                let src = self.read_immediate(&src)?;
+                let res = self.ptr_to_ptr(&src, cast_ty)?;
                 self.write_immediate(res, dest)?;
             }
 
@@ -126,13 +138,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(())
     }
 
-    pub fn misc_cast(
-        &mut self,
+    /// Handles 'IntToInt' and 'IntToFloat' casts.
+    pub fn int_to_int_or_float(
+        &self,
+        src: &ImmTy<'tcx, M::Provenance>,
+        cast_ty: Ty<'tcx>,
+    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
+        assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool());
+        assert!(cast_ty.is_floating_point() || cast_ty.is_integral() || cast_ty.is_char());
+
+        Ok(self.cast_from_int_like(src.to_scalar(), src.layout, cast_ty)?.into())
+    }
+
+    /// Handles 'FloatToFloat' and 'FloatToInt' casts.
+    pub fn float_to_float_or_int(
+        &self,
         src: &ImmTy<'tcx, M::Provenance>,
         cast_ty: Ty<'tcx>,
     ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
         use rustc_type_ir::sty::TyKind::*;
-        trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty);
 
         match src.layout.ty.kind() {
             // Floating point
@@ -142,47 +166,42 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Float(FloatTy::F64) => {
                 return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into());
             }
-            // The rest is integer/pointer-"like", including fn ptr casts
-            _ => assert!(
-                src.layout.ty.is_bool()
-                    || src.layout.ty.is_char()
-                    || src.layout.ty.is_integral()
-                    || src.layout.ty.is_any_ptr(),
-                "Unexpected cast from type {:?}",
-                src.layout.ty
-            ),
+            _ => {
+                bug!("Can't cast 'Float' type into {:?}", cast_ty);
+            }
         }
+    }
 
-        // # First handle non-scalar source values.
-
+    /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts.
+    pub fn ptr_to_ptr(
+        &self,
+        src: &ImmTy<'tcx, M::Provenance>,
+        cast_ty: Ty<'tcx>,
+    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
+        assert!(src.layout.ty.is_any_ptr());
+        assert!(cast_ty.is_unsafe_ptr());
         // Handle casting any ptr to raw ptr (might be a fat ptr).
-        if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() {
-            let dest_layout = self.layout_of(cast_ty)?;
-            if dest_layout.size == src.layout.size {
-                // Thin or fat pointer that just hast the ptr kind of target type changed.
-                return Ok(**src);
-            } else {
-                // Casting the metadata away from a fat ptr.
-                assert_eq!(src.layout.size, 2 * self.pointer_size());
-                assert_eq!(dest_layout.size, self.pointer_size());
-                assert!(src.layout.ty.is_unsafe_ptr());
-                return match **src {
-                    Immediate::ScalarPair(data, _) => Ok(data.into()),
-                    Immediate::Scalar(..) => span_bug!(
-                        self.cur_span(),
-                        "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
-                        *src,
-                        src.layout.ty,
-                        cast_ty
-                    ),
-                    Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
-                };
-            }
+        let dest_layout = self.layout_of(cast_ty)?;
+        if dest_layout.size == src.layout.size {
+            // Thin or fat pointer that just hast the ptr kind of target type changed.
+            return Ok(**src);
+        } else {
+            // Casting the metadata away from a fat ptr.
+            assert_eq!(src.layout.size, 2 * self.pointer_size());
+            assert_eq!(dest_layout.size, self.pointer_size());
+            assert!(src.layout.ty.is_unsafe_ptr());
+            return match **src {
+                Immediate::ScalarPair(data, _) => Ok(data.into()),
+                Immediate::Scalar(..) => span_bug!(
+                    self.cur_span(),
+                    "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
+                    *src,
+                    src.layout.ty,
+                    cast_ty
+                ),
+                Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
+            };
         }
-
-        // # The remaining source values are scalar and "int-like".
-        let scalar = src.to_scalar();
-        Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
     }
 
     pub fn pointer_expose_address_cast(
@@ -203,7 +222,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     }
 
     pub fn pointer_from_exposed_address_cast(
-        &mut self,
+        &self,
         src: &ImmTy<'tcx, M::Provenance>,
         cast_ty: Ty<'tcx>,
     ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
@@ -220,6 +239,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(Scalar::from_maybe_pointer(ptr, self).into())
     }
 
+    /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input
+    /// type (basically everything with a scalar layout) to int/float/char types.
     pub fn cast_from_int_like(
         &self,
         scalar: Scalar<M::Provenance>, // input value (there is no ScalarTy so we separate data+layout)
@@ -259,6 +280,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         })
     }
 
+    /// Low-level cast helper function. Converts an apfloat `f` into int or float types.
     fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance>
     where
         F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>,
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index d2e0a0dd240..f7d64f6d4f4 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -468,7 +468,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     #[inline]
     pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_freeze(self.tcx, self.param_env)
+        ty.is_freeze(*self.tcx, self.param_env)
     }
 
     pub fn load_mir(
@@ -598,7 +598,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // the last field).  Can't have foreign types here, how would we
                 // adjust alignment and size for them?
                 let field = layout.field(self, layout.fields.count() - 1);
-                let Some((unsized_size, unsized_align)) = self.size_and_align_of(metadata, &field)? else {
+                let Some((unsized_size, mut unsized_align)) = self.size_and_align_of(metadata, &field)? else {
                     // A field with an extern type. We don't know the actual dynamic size
                     // or the alignment.
                     return Ok(None);
@@ -614,6 +614,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // Return the sum of sizes and max of aligns.
                 let size = sized_size + unsized_size; // `Size` addition
 
+                // Packed types ignore the alignment of their fields.
+                if let ty::Adt(def, _) = layout.ty.kind() {
+                    if def.repr().packed() {
+                        unsized_align = sized_align;
+                    }
+                }
+
                 // Choose max of two known alignments (combined value must
                 // be aligned according to more restrictive of the two).
                 let align = sized_align.max(unsized_align);
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index f72ae7413e3..6809a42dc45 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -15,7 +15,7 @@
 //! that contains allocations whose mutability we cannot identify.)
 
 use super::validity::RefTracking;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_middle::mir::interpret::InterpResult;
@@ -37,7 +37,7 @@ pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine<
     ExtraFnVal = !,
     FrameExtra = (),
     AllocExtra = (),
-    MemoryMap = FxHashMap<AllocId, (MemoryKind<T>, Allocation)>,
+    MemoryMap = FxIndexMap<AllocId, (MemoryKind<T>, Allocation)>,
 >;
 
 struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> {
@@ -47,7 +47,7 @@ struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_ev
     ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, InternMode)>,
     /// A list of all encountered allocations. After type-based interning, we traverse this list to
     /// also intern allocations that are only referenced by a raw pointer or inside a union.
-    leftover_allocations: &'rt mut FxHashSet<AllocId>,
+    leftover_allocations: &'rt mut FxIndexSet<AllocId>,
     /// The root kind of the value that we're looking at. This field is never mutated for a
     /// particular allocation. It is primarily used to make as many allocations as possible
     /// read-only so LLVM can place them in const memory.
@@ -79,7 +79,7 @@ struct IsStaticOrFn;
 /// to account for (e.g. for vtables).
 fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>(
     ecx: &'rt mut InterpCx<'mir, 'tcx, M>,
-    leftover_allocations: &'rt mut FxHashSet<AllocId>,
+    leftover_allocations: &'rt mut FxIndexSet<AllocId>,
     alloc_id: AllocId,
     mode: InternMode,
     ty: Option<Ty<'tcx>>,
@@ -114,7 +114,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
     if let InternMode::Static(mutability) = mode {
         // For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume
         // no interior mutability.
-        let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env));
+        let frozen = ty.map_or(true, |ty| ty.is_freeze(*ecx.tcx, ecx.param_env));
         // For statics, allocation mutability is the combination of place mutability and
         // type mutability.
         // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
@@ -355,7 +355,7 @@ pub fn intern_const_alloc_recursive<
     // `leftover_allocations` collects *all* allocations we see, because some might not
     // be available in a typed way. They get interned at the end.
     let mut ref_tracking = RefTracking::empty();
-    let leftover_allocations = &mut FxHashSet::default();
+    let leftover_allocations = &mut FxIndexSet::default();
 
     // start with the outermost allocation
     intern_shallow(
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 8637d6a7767..b92a6878847 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -7,7 +7,9 @@ use std::convert::TryFrom;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{
     self,
-    interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar},
+    interpret::{
+        Allocation, ConstAllocation, ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar,
+    },
     BinOp, NonDivergingIntrinsic,
 };
 use rustc_middle::ty;
@@ -23,7 +25,6 @@ use super::{
 };
 
 mod caller_location;
-mod type_name;
 
 fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<Prov> {
     let size = match kind {
@@ -42,6 +43,13 @@ fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<
     Scalar::from_uint(bits_out, size)
 }
 
+/// Directly returns an `Allocation` containing an absolute path representation of the given type.
+pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
+    let path = crate::util::type_name(tcx, ty);
+    let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
+    tcx.intern_const_alloc(alloc)
+}
+
 /// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
 /// inside an `InterpCx` and instead have their value computed directly from rustc internal info.
 pub(crate) fn eval_nullary_intrinsic<'tcx>(
@@ -55,7 +63,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
     Ok(match name {
         sym::type_name => {
             ensure_monomorphic_enough(tcx, tp_ty)?;
-            let alloc = type_name::alloc_type_name(tcx, tp_ty);
+            let alloc = alloc_type_name(tcx, tp_ty);
             ConstValue::Slice { data: alloc, start: 0, end: alloc.inner().len() }
         }
         sym::needs_drop => {
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 530e252b7c0..351152eba01 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -426,7 +426,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     type ExtraFnVal = !;
 
     type MemoryMap =
-        rustc_data_structures::fx::FxHashMap<AllocId, (MemoryKind<Self::MemoryKind>, Allocation)>;
+        rustc_data_structures::fx::FxIndexMap<AllocId, (MemoryKind<Self::MemoryKind>, Allocation)>;
     const GLOBAL_KIND: Option<Self::MemoryKind> = None; // no copying of globals from `tcx` to machine memory
 
     type AllocExtra = ();
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index ed155fbfef0..e5e015c1e18 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -794,7 +794,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             todo.extend(static_roots);
             while let Some(id) = todo.pop() {
                 if reachable.insert(id) {
-                    // This is a new allocation, add the allocation it points to to `todo`.
+                    // This is a new allocation, add the allocation it points to `todo`.
                     if let Some((_, alloc)) = self.memory.alloc_map.get(id) {
                         todo.extend(
                             alloc.provenance().values().filter_map(|prov| prov.get_alloc_id()),
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 719588a936c..dd00678aa0c 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -4,7 +4,7 @@
 use rustc_hir::def::Namespace;
 use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
-use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, Ty};
+use rustc_middle::ty::{ConstInt, Ty};
 use rustc_middle::{mir, ty};
 use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size, TagEncoding};
 use rustc_target::abi::{VariantIdx, Variants};
@@ -554,13 +554,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         val: &mir::ConstantKind<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
+        // FIXME(const_prop): normalization needed b/c const prop lint in
+        // `mir_drops_elaborated_and_const_checked`, which happens before
+        // optimized MIR. Only after optimizing the MIR can we guarantee
+        // that the `RevealAll` pass has happened and that the body's consts
+        // are normalized, so any call to resolve before that needs to be
+        // manually normalized.
+        let val = self.tcx.normalize_erasing_regions(self.param_env, *val);
         match val {
             mir::ConstantKind::Ty(ct) => {
                 match ct.kind() {
                     ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => {
                         throw_inval!(TooGeneric)
                     }
-                    ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => {
+                    ty::ConstKind::Error(reported) => {
                         throw_inval!(AlreadyReported(reported))
                     }
                     ty::ConstKind::Unevaluated(uv) => {
@@ -585,7 +592,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     }
                 }
             }
-            mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, *ty, layout),
+            mir::ConstantKind::Val(val, ty) => self.const_val_to_op(val, ty, layout),
             mir::ConstantKind::Unevaluated(uv, _) => {
                 let instance = self.resolve(uv.def, uv.substs)?;
                 Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into())
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 50a82aa0e72..57e40e168fa 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -35,7 +35,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 assert_eq!(discr.layout.ty, switch_ty);
 
                 // Branch to the `otherwise` case by default, if no match is found.
-                assert!(!targets.iter().is_empty());
                 let mut target_block = targets.otherwise();
 
                 for (const_int, target) in targets.iter() {
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index d4146c24241..8aa56c275d9 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -15,7 +15,6 @@ use rustc_middle::mir::interpret::InterpError;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_span::symbol::{sym, Symbol};
-use rustc_span::DUMMY_SP;
 use rustc_target::abi::{Abi, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange};
 
 use std::hash::Hash;
@@ -726,7 +725,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     ) -> InterpResult<'tcx> {
         // Special check preventing `UnsafeCell` inside unions in the inner part of constants.
         if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) {
-            if !op.layout.ty.is_freeze(self.ecx.tcx.at(DUMMY_SP), self.ecx.param_env) {
+            if !op.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) {
                 throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });
             }
         }
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 230f841cf4d..443c01fdb90 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -22,7 +22,6 @@ Rust MIR: a lowered representation of Rust.
 #![feature(yeet_expr)]
 #![feature(is_some_and)]
 #![recursion_limit = "256"]
-#![allow(rustc::potential_query_instability)]
 
 #[macro_use]
 extern crate tracing;
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 b77b213b51a..335992342a6 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -8,7 +8,6 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
-use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::{
     self, ImplSource, Obligation, ObligationCause, SelectionContext,
 };
@@ -92,7 +91,7 @@ impl Qualif for HasMutInterior {
     }
 
     fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
-        !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
+        !ty.is_freeze(cx.tcx, cx.param_env)
     }
 
     fn in_adt_inherently<'tcx>(
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index 60c1e495029..805e6096b35 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -8,7 +8,6 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementK
 use rustc_mir_dataflow::fmt::DebugWithContext;
 use rustc_mir_dataflow::JoinSemiLattice;
 use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces};
-use rustc_span::DUMMY_SP;
 
 use std::fmt;
 use std::marker::PhantomData;
@@ -120,10 +119,7 @@ where
     ///
     /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
     fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
-        !place
-            .ty(self.ccx.body, self.ccx.tcx)
-            .ty
-            .is_freeze(self.ccx.tcx.at(DUMMY_SP), self.ccx.param_env)
+        !place.ty(self.ccx.body, self.ccx.tcx).ty.is_freeze(self.ccx.tcx, self.ccx.param_env)
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 4b219300739..f48bcd90809 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -41,19 +41,14 @@ pub struct PromoteTemps<'tcx> {
 }
 
 impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
-    fn phase_change(&self) -> Option<MirPhase> {
-        Some(MirPhase::Analysis(AnalysisPhase::Initial))
-    }
-
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // There's not really any point in promoting errorful MIR.
         //
         // This does not include MIR that failed const-checking, which we still try to promote.
-        if body.return_ty().references_error() {
-            tcx.sess.delay_span_bug(body.span, "PromoteTemps: MIR had errors");
+        if let Err(_) = body.return_ty().error_reported() {
+            debug!("PromoteTemps: MIR had errors");
             return;
         }
-
         if body.source.promoted.is_some() {
             return;
         }
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 87b7c55bf7f..81b82a21fa1 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -235,9 +235,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             // `Operand::Copy` is only supposed to be used with `Copy` types.
             if let Operand::Copy(place) = operand {
                 let ty = place.ty(&self.body.local_decls, self.tcx).ty;
-                let span = self.body.source_info(location).span;
 
-                if !ty.is_copy_modulo_regions(self.tcx.at(span), self.param_env) {
+                if !ty.is_copy_modulo_regions(self.tcx, self.param_env) {
                     self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty));
                 }
             }
@@ -284,7 +283,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         this.fail(
                         location,
                         format!(
-                            "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is {:?}",
+                            "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
                             parent, f, ty, f_ty
                         )
                     )
@@ -556,21 +555,36 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 check_kinds!(a, "Cannot shallow init type {:?}", ty::RawPtr(..));
             }
             Rvalue::Cast(kind, operand, target_type) => {
+                let op_ty = operand.ty(self.body, self.tcx);
                 match kind {
                     CastKind::DynStar => {
                         // FIXME(dyn-star): make sure nothing needs to be done here.
                     }
-                    // Nothing to check here
+                    // FIXME: Add Checks for these
                     CastKind::PointerFromExposedAddress
                     | CastKind::PointerExposeAddress
                     | CastKind::Pointer(_) => {}
-                    _ => {
-                        let op_ty = operand.ty(self.body, self.tcx);
-                        if op_ty.is_enum() {
+                    CastKind::IntToInt | CastKind::IntToFloat => {
+                        let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool();
+                        let target_valid = target_type.is_numeric() || target_type.is_char();
+                        if !input_valid || !target_valid {
+                            self.fail(
+                                location,
+                                format!("Wrong cast kind {kind:?} for the type {op_ty}",),
+                            );
+                        }
+                    }
+                    CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
+                        if !(op_ty.is_any_ptr() && target_type.is_unsafe_ptr()) {
+                            self.fail(location, "Can't cast {op_ty} into 'Ptr'");
+                        }
+                    }
+                    CastKind::FloatToFloat | CastKind::FloatToInt => {
+                        if !op_ty.is_floating_point() || !target_type.is_numeric() {
                             self.fail(
                                 location,
                                 format!(
-                                    "enum -> int casts should go through `Rvalue::Discriminant`: {operand:?}:{op_ty} as {target_type}",
+                                    "Trying to cast non 'Float' as {kind:?} into {target_type:?}"
                                 ),
                             );
                         }
diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs
index af9d83f0609..5446ccb1a47 100644
--- a/compiler/rustc_const_eval/src/util/call_kind.rs
+++ b/compiler/rustc_const_eval/src/util/call_kind.rs
@@ -3,7 +3,7 @@
 //! context.
 
 use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::LangItemGroup;
+use rustc_hir::lang_items;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt};
 use rustc_span::symbol::Ident;
@@ -74,22 +74,24 @@ pub fn call_kind<'tcx>(
         }
     });
 
-    let fn_call = parent
-        .and_then(|p| tcx.lang_items().group(LangItemGroup::Fn).iter().find(|did| **did == p));
+    let fn_call = parent.and_then(|p| {
+        lang_items::FN_TRAITS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p)
+    });
 
-    let operator = (!from_hir_call)
-        .then(|| parent)
-        .flatten()
-        .and_then(|p| tcx.lang_items().group(LangItemGroup::Op).iter().find(|did| **did == p));
+    let operator = if !from_hir_call && let Some(p) = parent {
+        lang_items::OPERATORS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p)
+    } else {
+        None
+    };
 
     let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
 
     // Check for a 'special' use of 'self' -
     // an FnOnce call, an operator (e.g. `<<`), or a
     // deref coercion.
-    let kind = if let Some(&trait_id) = fn_call {
+    let kind = if let Some(trait_id) = fn_call {
         Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) })
-    } else if let Some(&trait_id) = operator {
+    } else if let Some(trait_id) = operator {
         Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) })
     } else if is_deref {
         let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index 7a05cfd235f..4d0f81a4060 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -4,9 +4,11 @@ mod call_kind;
 pub mod collect_writes;
 mod find_self_call;
 mod might_permit_raw_init;
+mod type_name;
 
 pub use self::aggregate::expand_aggregate;
 pub use self::alignment::is_disaligned;
 pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
 pub use self::find_self_call::find_self_call;
 pub use self::might_permit_raw_init::might_permit_raw_init;
+pub use self::type_name::type_name;
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index 7e4c5fcb031..08a6d69b8e4 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -1,7 +1,6 @@
 use rustc_data_structures::intern::Interned;
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::definitions::DisambiguatedDefPathData;
-use rustc_middle::mir::interpret::{Allocation, ConstAllocation};
 use rustc_middle::ty::{
     self,
     print::{PrettyPrinter, Print, Printer},
@@ -74,18 +73,10 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
     }
 
     fn print_dyn_existential(
-        mut self,
+        self,
         predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
     ) -> Result<Self::DynExistential, Self::Error> {
-        let mut first = true;
-        for p in predicates {
-            if !first {
-                write!(self, "+")?;
-            }
-            first = false;
-            self = p.print(self)?;
-        }
-        Ok(self)
+        self.pretty_print_dyn_existential(predicates)
     }
 
     fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
@@ -179,6 +170,11 @@ impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
 
         Ok(self)
     }
+
+    fn should_print_verbose(&self) -> bool {
+        // `std::any::type_name` should never print verbose type names
+        false
+    }
 }
 
 impl Write for AbsolutePathPrinter<'_> {
@@ -188,9 +184,6 @@ impl Write for AbsolutePathPrinter<'_> {
     }
 }
 
-/// Directly returns an `Allocation` containing an absolute path representation of the given type.
-pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
-    let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
-    let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
-    tcx.intern_const_alloc(alloc)
+pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String {
+    AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path
 }
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 9daa21ef6b1..5152d5ab046 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -25,7 +25,7 @@ smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dang
 stable_deref_trait = "1.0.0"
 stacker = "0.1.14"
 tempfile = "3.2"
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
 tracing = "0.1"
 
 [dependencies.parking_lot]
diff --git a/compiler/rustc_data_structures/src/flock/linux.rs b/compiler/rustc_data_structures/src/flock/linux.rs
index bb3ecfbc370..9ed26e49006 100644
--- a/compiler/rustc_data_structures/src/flock/linux.rs
+++ b/compiler/rustc_data_structures/src/flock/linux.rs
@@ -14,12 +14,7 @@ pub struct Lock {
 
 impl Lock {
     pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result<Lock> {
-        let file = OpenOptions::new()
-            .read(true)
-            .write(true)
-            .create(create)
-            .mode(libc::S_IRWXU as u32)
-            .open(p)?;
+        let file = OpenOptions::new().read(true).write(true).create(create).mode(0o600).open(p)?;
 
         let mut operation = if exclusive { libc::LOCK_EX } else { libc::LOCK_SH };
         if !wait {
diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
index 3d91bcade59..e8efbd09a2c 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
@@ -29,8 +29,8 @@ impl<N: Idx + Ord> VecGraph<N> {
         // Store the *target* of each edge into `edge_targets`.
         let edge_targets: Vec<N> = edge_pairs.iter().map(|&(_, target)| target).collect();
 
-        // Create the *edge starts* array. We are iterating over over
-        // the (sorted) edge pairs. We maintain the invariant that the
+        // Create the *edge starts* array. We are iterating over the
+        // (sorted) edge pairs. We maintain the invariant that the
         // length of the `node_starts` array is enough to store the
         // current source node -- so when we see that the source node
         // for an edge is greater than the current length, we grow the
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 467ac401d08..3a2000233c5 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -22,6 +22,7 @@
 #![feature(new_uninit)]
 #![feature(once_cell)]
 #![feature(rustc_attrs)]
+#![feature(negative_impls)]
 #![feature(test)]
 #![feature(thread_id_value)]
 #![feature(vec_into_raw_parts)]
@@ -86,6 +87,7 @@ pub mod steal;
 pub mod tagged_ptr;
 pub mod temp_dir;
 pub mod unhash;
+pub mod unord;
 
 pub use ena::undo_log;
 pub use ena::unify;
diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs
index 4fda3adb7b8..406f0270dcc 100644
--- a/compiler/rustc_data_structures/src/sso/set.rs
+++ b/compiler/rustc_data_structures/src/sso/set.rs
@@ -27,7 +27,7 @@ pub struct SsoHashSet<T> {
     map: SsoHashMap<T, ()>,
 }
 
-/// Adapter function used ot return
+/// Adapter function used to return
 /// result if SsoHashMap functions into
 /// result SsoHashSet should return.
 #[inline(always)]
diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs
index f016c391fe7..cf616203842 100644
--- a/compiler/rustc_data_structures/src/transitive_relation.rs
+++ b/compiler/rustc_data_structures/src/transitive_relation.rs
@@ -1,5 +1,5 @@
 use crate::frozen::Frozen;
-use crate::fx::FxIndexSet;
+use crate::fx::{FxHashSet, FxIndexSet};
 use rustc_index::bit_set::BitMatrix;
 use std::fmt::Debug;
 use std::hash::Hash;
@@ -16,7 +16,7 @@ pub struct TransitiveRelationBuilder<T> {
 
     // List of base edges in the graph. Require to compute transitive
     // closure.
-    edges: Vec<Edge>,
+    edges: FxHashSet<Edge>,
 }
 
 #[derive(Debug)]
@@ -52,10 +52,10 @@ impl<T: Eq + Hash> Default for TransitiveRelationBuilder<T> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug, Hash)]
 struct Index(usize);
 
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 struct Edge {
     source: Index,
     target: Index,
@@ -99,9 +99,7 @@ impl<T: Eq + Hash + Copy> TransitiveRelationBuilder<T> {
         let a = self.add_index(a);
         let b = self.add_index(b);
         let edge = Edge { source: a, target: b };
-        if !self.edges.contains(&edge) {
-            self.edges.push(edge);
-        }
+        self.edges.insert(edge);
     }
 
     /// Compute the transitive closure derived from the edges, and converted to
diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs
new file mode 100644
index 00000000000..c015f1232cd
--- /dev/null
+++ b/compiler/rustc_data_structures/src/unord.rs
@@ -0,0 +1,382 @@
+//! This module contains collection types that don't expose their internal
+//! ordering. This is a useful property for deterministic computations, such
+//! as required by the query system.
+
+use rustc_hash::{FxHashMap, FxHashSet};
+use smallvec::SmallVec;
+use std::{
+    borrow::Borrow,
+    hash::Hash,
+    iter::{Product, Sum},
+};
+
+use crate::{
+    fingerprint::Fingerprint,
+    stable_hasher::{HashStable, StableHasher, ToStableHashKey},
+};
+
+/// `UnordItems` is the order-less version of `Iterator`. It only contains methods
+/// that don't (easily) expose an ordering of the underlying items.
+///
+/// Most methods take an `Fn` where the `Iterator`-version takes an `FnMut`. This
+/// is to reduce the risk of accidentally leaking the internal order via the closure
+/// environment. Otherwise one could easily do something like
+///
+/// ```rust,ignore (pseudo code)
+/// let mut ordered = vec![];
+/// unordered_items.all(|x| ordered.push(x));
+/// ```
+///
+/// It's still possible to do the same thing with an `Fn` by using interior mutability,
+/// but the chance of doing it accidentally is reduced.
+pub struct UnordItems<T, I: Iterator<Item = T>>(I);
+
+impl<T, I: Iterator<Item = T>> UnordItems<T, I> {
+    #[inline]
+    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> UnordItems<U, impl Iterator<Item = U>> {
+        UnordItems(self.0.map(f))
+    }
+
+    #[inline]
+    pub fn all<U, F: Fn(T) -> bool>(mut self, f: F) -> bool {
+        self.0.all(f)
+    }
+
+    #[inline]
+    pub fn any<U, F: Fn(T) -> bool>(mut self, f: F) -> bool {
+        self.0.any(f)
+    }
+
+    #[inline]
+    pub fn filter<U, F: Fn(&T) -> bool>(self, f: F) -> UnordItems<T, impl Iterator<Item = T>> {
+        UnordItems(self.0.filter(f))
+    }
+
+    #[inline]
+    pub fn filter_map<U, F: Fn(T) -> Option<U>>(
+        self,
+        f: F,
+    ) -> UnordItems<U, impl Iterator<Item = U>> {
+        UnordItems(self.0.filter_map(f))
+    }
+
+    #[inline]
+    pub fn max(self) -> Option<T>
+    where
+        T: Ord,
+    {
+        self.0.max()
+    }
+
+    #[inline]
+    pub fn min(self) -> Option<T>
+    where
+        T: Ord,
+    {
+        self.0.min()
+    }
+
+    #[inline]
+    pub fn sum<S>(self) -> S
+    where
+        S: Sum<T>,
+    {
+        self.0.sum()
+    }
+
+    #[inline]
+    pub fn product<S>(self) -> S
+    where
+        S: Product<T>,
+    {
+        self.0.product()
+    }
+
+    #[inline]
+    pub fn count(self) -> usize {
+        self.0.count()
+    }
+}
+
+impl<'a, T: Clone + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
+    #[inline]
+    pub fn cloned(self) -> UnordItems<T, impl Iterator<Item = T>> {
+        UnordItems(self.0.cloned())
+    }
+}
+
+impl<'a, T: Copy + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
+    #[inline]
+    pub fn copied(self) -> UnordItems<T, impl Iterator<Item = T>> {
+        UnordItems(self.0.copied())
+    }
+}
+
+impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
+    pub fn into_sorted<HCX>(self, hcx: &HCX) -> Vec<T>
+    where
+        T: ToStableHashKey<HCX>,
+    {
+        let mut items: Vec<T> = self.0.collect();
+        items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
+        items
+    }
+
+    pub fn into_sorted_small_vec<HCX, const LEN: usize>(self, hcx: &HCX) -> SmallVec<[T; LEN]>
+    where
+        T: ToStableHashKey<HCX>,
+    {
+        let mut items: SmallVec<[T; LEN]> = self.0.collect();
+        items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
+        items
+    }
+}
+
+/// This is a set collection type that tries very hard to not expose
+/// any internal iteration. This is a useful property when trying to
+/// uphold the determinism invariants imposed by the query system.
+///
+/// This collection type is a good choice for set-like collections the
+/// keys of which don't have a semantic ordering.
+///
+/// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
+/// for more information.
+#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
+pub struct UnordSet<V: Eq + Hash> {
+    inner: FxHashSet<V>,
+}
+
+impl<V: Eq + Hash> Default for UnordSet<V> {
+    fn default() -> Self {
+        Self { inner: FxHashSet::default() }
+    }
+}
+
+impl<V: Eq + Hash> UnordSet<V> {
+    #[inline]
+    pub fn new() -> Self {
+        Self { inner: Default::default() }
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.inner.len()
+    }
+
+    #[inline]
+    pub fn insert(&mut self, v: V) -> bool {
+        self.inner.insert(v)
+    }
+
+    #[inline]
+    pub fn contains<Q: ?Sized>(&self, v: &Q) -> bool
+    where
+        V: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        self.inner.contains(v)
+    }
+
+    #[inline]
+    pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> {
+        UnordItems(self.inner.iter())
+    }
+
+    #[inline]
+    pub fn into_items(self) -> UnordItems<V, impl Iterator<Item = V>> {
+        UnordItems(self.inner.into_iter())
+    }
+
+    // We can safely extend this UnordSet from a set of unordered values because that
+    // won't expose the internal ordering anywhere.
+    #[inline]
+    pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) {
+        self.inner.extend(items.0)
+    }
+}
+
+impl<V: Hash + Eq> Extend<V> for UnordSet<V> {
+    fn extend<T: IntoIterator<Item = V>>(&mut self, iter: T) {
+        self.inner.extend(iter)
+    }
+}
+
+impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordSet<V> {
+    #[inline]
+    fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
+        hash_iter_order_independent(self.inner.iter(), hcx, hasher);
+    }
+}
+
+/// This is a map collection type that tries very hard to not expose
+/// any internal iteration. This is a useful property when trying to
+/// uphold the determinism invariants imposed by the query system.
+///
+/// This collection type is a good choice for map-like collections the
+/// keys of which don't have a semantic ordering.
+///
+/// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
+/// for more information.
+#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
+pub struct UnordMap<K: Eq + Hash, V> {
+    inner: FxHashMap<K, V>,
+}
+
+impl<K: Eq + Hash, V> Default for UnordMap<K, V> {
+    fn default() -> Self {
+        Self { inner: FxHashMap::default() }
+    }
+}
+
+impl<K: Hash + Eq, V> Extend<(K, V)> for UnordMap<K, V> {
+    fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
+        self.inner.extend(iter)
+    }
+}
+
+impl<K: Eq + Hash, V> UnordMap<K, V> {
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.inner.len()
+    }
+
+    #[inline]
+    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
+        self.inner.insert(k, v)
+    }
+
+    #[inline]
+    pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
+    where
+        K: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        self.inner.contains_key(k)
+    }
+
+    #[inline]
+    pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator<Item = (&'a K, &'a V)>> {
+        UnordItems(self.inner.iter())
+    }
+
+    #[inline]
+    pub fn into_items(self) -> UnordItems<(K, V), impl Iterator<Item = (K, V)>> {
+        UnordItems(self.inner.into_iter())
+    }
+
+    // We can safely extend this UnordMap from a set of unordered values because that
+    // won't expose the internal ordering anywhere.
+    #[inline]
+    pub fn extend<I: Iterator<Item = (K, V)>>(&mut self, items: UnordItems<(K, V), I>) {
+        self.inner.extend(items.0)
+    }
+}
+
+impl<HCX, K: Hash + Eq + HashStable<HCX>, V: HashStable<HCX>> HashStable<HCX> for UnordMap<K, V> {
+    #[inline]
+    fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
+        hash_iter_order_independent(self.inner.iter(), hcx, hasher);
+    }
+}
+
+/// This is a collection type that tries very hard to not expose
+/// any internal iteration. This is a useful property when trying to
+/// uphold the determinism invariants imposed by the query system.
+///
+/// This collection type is a good choice for collections the
+/// keys of which don't have a semantic ordering and don't implement
+/// `Hash` or `Eq`.
+///
+/// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
+/// for more information.
+#[derive(Default, Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
+pub struct UnordBag<V> {
+    inner: Vec<V>,
+}
+
+impl<V> UnordBag<V> {
+    #[inline]
+    pub fn new() -> Self {
+        Self { inner: Default::default() }
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.inner.len()
+    }
+
+    #[inline]
+    pub fn push(&mut self, v: V) {
+        self.inner.push(v);
+    }
+
+    #[inline]
+    pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> {
+        UnordItems(self.inner.iter())
+    }
+
+    #[inline]
+    pub fn into_items(self) -> UnordItems<V, impl Iterator<Item = V>> {
+        UnordItems(self.inner.into_iter())
+    }
+
+    // We can safely extend this UnordSet from a set of unordered values because that
+    // won't expose the internal ordering anywhere.
+    #[inline]
+    pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) {
+        self.inner.extend(items.0)
+    }
+}
+
+impl<T> Extend<T> for UnordBag<T> {
+    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+        self.inner.extend(iter)
+    }
+}
+
+impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordBag<V> {
+    #[inline]
+    fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
+        hash_iter_order_independent(self.inner.iter(), hcx, hasher);
+    }
+}
+
+fn hash_iter_order_independent<
+    HCX,
+    T: HashStable<HCX>,
+    I: Iterator<Item = T> + ExactSizeIterator,
+>(
+    mut it: I,
+    hcx: &mut HCX,
+    hasher: &mut StableHasher,
+) {
+    let len = it.len();
+    len.hash_stable(hcx, hasher);
+
+    match len {
+        0 => {
+            // We're done
+        }
+        1 => {
+            // No need to instantiate a hasher
+            it.next().unwrap().hash_stable(hcx, hasher);
+        }
+        _ => {
+            let mut accumulator = Fingerprint::ZERO;
+            for item in it {
+                let mut item_hasher = StableHasher::new();
+                item.hash_stable(hcx, &mut item_hasher);
+                let item_fingerprint: Fingerprint = item_hasher.finish();
+                accumulator = accumulator.combine_commutative(item_fingerprint);
+            }
+            accumulator.hash_stable(hcx, hasher);
+        }
+    }
+}
+
+// Do not implement IntoIterator for the collections in this module.
+// They only exist to hide iteration order in the first place.
+impl<T> !IntoIterator for UnordBag<T> {}
+impl<V> !IntoIterator for UnordSet<V> {}
+impl<K, V> !IntoIterator for UnordMap<K, V> {}
+impl<T, I> !IntoIterator for UnordItems<T, I> {}
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 7d5604fcabc..cf4bcc7c158 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -35,7 +35,7 @@ use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, Tr
 use rustc_session::cstore::MetadataLoader;
 use rustc_session::getopts;
 use rustc_session::lint::{Lint, LintId};
-use rustc_session::{config, DiagnosticOutput, Session};
+use rustc_session::{config, Session};
 use rustc_session::{early_error, early_error_no_abort, early_warn};
 use rustc_span::source_map::{FileLoader, FileName};
 use rustc_span::symbol::sym;
@@ -147,19 +147,21 @@ pub struct RunCompiler<'a, 'b> {
     at_args: &'a [String],
     callbacks: &'b mut (dyn Callbacks + Send),
     file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    emitter: Option<Box<dyn Write + Send>>,
     make_codegen_backend:
         Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
 }
 
 impl<'a, 'b> RunCompiler<'a, 'b> {
     pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self {
-        Self { at_args, callbacks, file_loader: None, emitter: None, make_codegen_backend: None }
+        Self { at_args, callbacks, file_loader: None, make_codegen_backend: None }
     }
 
     /// Set a custom codegen backend.
     ///
-    /// Used by cg_clif.
+    /// Has no uses within this repository, but is used by bjorn3 for "the
+    /// hotswapping branch of cg_clif" for "setting the codegen backend from a
+    /// custom driver where the custom codegen backend has arbitrary data."
+    /// (See #102759.)
     pub fn set_make_codegen_backend(
         &mut self,
         make_codegen_backend: Option<
@@ -170,17 +172,11 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
         self
     }
 
-    /// Emit diagnostics to the specified location.
-    ///
-    /// Used by RLS.
-    pub fn set_emitter(&mut self, emitter: Option<Box<dyn Write + Send>>) -> &mut Self {
-        self.emitter = emitter;
-        self
-    }
-
     /// Load files from sources other than the file system.
     ///
-    /// Used by RLS.
+    /// Has no uses within this repository, but may be used in the future by
+    /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for
+    /// running rustc without having to save". (See #102759.)
     pub fn set_file_loader(
         &mut self,
         file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
@@ -191,27 +187,20 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
 
     /// Parse args and run the compiler.
     pub fn run(self) -> interface::Result<()> {
-        run_compiler(
-            self.at_args,
-            self.callbacks,
-            self.file_loader,
-            self.emitter,
-            self.make_codegen_backend,
-        )
+        run_compiler(self.at_args, self.callbacks, self.file_loader, self.make_codegen_backend)
     }
 }
+
 fn run_compiler(
     at_args: &[String],
     callbacks: &mut (dyn Callbacks + Send),
     file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    emitter: Option<Box<dyn Write + Send>>,
     make_codegen_backend: Option<
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
     >,
 ) -> interface::Result<()> {
     let args = args::arg_expand_all(at_args);
 
-    let diagnostic_output = emitter.map_or(DiagnosticOutput::Default, DiagnosticOutput::Raw);
     let Some(matches) = handle_options(&args) else { return Ok(()) };
 
     let sopts = config::build_session_options(&matches);
@@ -233,7 +222,6 @@ fn run_compiler(
         output_file: ofile,
         output_dir: odir,
         file_loader,
-        diagnostic_output,
         lint_caps: Default::default(),
         parse_sess_created: None,
         register_lints: None,
@@ -439,18 +427,6 @@ fn run_compiler(
     })
 }
 
-#[cfg(unix)]
-pub fn set_sigpipe_handler() {
-    unsafe {
-        // Set the SIGPIPE signal handler, so that an EPIPE
-        // will cause rustc to terminate, as expected.
-        assert_ne!(libc::signal(libc::SIGPIPE, libc::SIG_DFL), libc::SIG_ERR);
-    }
-}
-
-#[cfg(windows)]
-pub fn set_sigpipe_handler() {}
-
 // Extract output directory and file from matches.
 fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
     let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
@@ -1224,6 +1200,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
         false,
         None,
         false,
+        false,
     ));
     let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
 
diff --git a/compiler/rustc_driver/src/session_diagnostics.rs b/compiler/rustc_driver/src/session_diagnostics.rs
index 289baf17773..c1bc1089114 100644
--- a/compiler/rustc_driver/src/session_diagnostics.rs
+++ b/compiler/rustc_driver/src/session_diagnostics.rs
@@ -1,39 +1,39 @@
 use rustc_macros::Diagnostic;
 
 #[derive(Diagnostic)]
-#[diag(driver::rlink_unable_to_read)]
+#[diag(driver_rlink_unable_to_read)]
 pub(crate) struct RlinkUnableToRead {
     pub err: std::io::Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(driver::rlink_wrong_file_type)]
+#[diag(driver_rlink_wrong_file_type)]
 pub(crate) struct RLinkWrongFileType;
 
 #[derive(Diagnostic)]
-#[diag(driver::rlink_empty_version_number)]
+#[diag(driver_rlink_empty_version_number)]
 pub(crate) struct RLinkEmptyVersionNumber;
 
 #[derive(Diagnostic)]
-#[diag(driver::rlink_encoding_version_mismatch)]
+#[diag(driver_rlink_encoding_version_mismatch)]
 pub(crate) struct RLinkEncodingVersionMismatch {
     pub version_array: String,
     pub rlink_version: u32,
 }
 
 #[derive(Diagnostic)]
-#[diag(driver::rlink_rustc_version_mismatch)]
+#[diag(driver_rlink_rustc_version_mismatch)]
 pub(crate) struct RLinkRustcVersionMismatch<'a> {
     pub rustc_version: String,
     pub current_version: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(driver::rlink_no_a_file)]
+#[diag(driver_rlink_no_a_file)]
 pub(crate) struct RlinkNotAFile;
 
 #[derive(Diagnostic)]
-#[diag(driver::unpretty_dump_fail)]
+#[diag(driver_unpretty_dump_fail)]
 pub(crate) struct UnprettyDumpFail {
     pub path: String,
     pub err: String,
diff --git a/compiler/rustc_error_codes/src/error_codes/E0210.md b/compiler/rustc_error_codes/src/error_codes/E0210.md
index dc2fd9b0ca0..41263e5e3f5 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0210.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0210.md
@@ -76,7 +76,5 @@ Let `Ti` be the first such type.
 For information on the design of the orphan rules,
 see [RFC 2451] and [RFC 1023].
 
-For information on the design of the orphan rules, see [RFC 1023].
-
 [RFC 2451]: https://rust-lang.github.io/rfcs/2451-re-rebalancing-coherence.html
 [RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md
diff --git a/compiler/rustc_error_codes/src/error_codes/E0382.md b/compiler/rustc_error_codes/src/error_codes/E0382.md
index d1408a06296..cbc4980f8ca 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0382.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0382.md
@@ -61,7 +61,7 @@ with `#[derive(Clone)]`.
 
 Some types have no ownership semantics at all and are trivial to duplicate. An
 example is `i32` and the other number types. We don't have to call `.clone()` to
-clone them, because they are marked `Copy` in addition to `Clone`.  Implicit
+clone them, because they are marked `Copy` in addition to `Clone`. Implicit
 cloning is more convenient in this case. We can mark our own types `Copy` if
 all their members also are marked `Copy`.
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0732.md b/compiler/rustc_error_codes/src/error_codes/E0732.md
index 7347e6654c5..9536fdbf0df 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0732.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0732.md
@@ -3,8 +3,6 @@ An `enum` with a discriminant must specify a `#[repr(inttype)]`.
 Erroneous code example:
 
 ```compile_fail,E0732
-#![feature(arbitrary_enum_discriminant)]
-
 enum Enum { // error!
     Unit = 1,
     Tuple() = 2,
@@ -20,8 +18,6 @@ is a well-defined way to extract a variant's discriminant from a value;
 for instance:
 
 ```
-#![feature(arbitrary_enum_discriminant)]
-
 #[repr(u8)]
 enum Enum {
     Unit = 3,
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
index 0d0388a039e..966a421bcf0 100644
--- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -34,6 +34,8 @@ codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, fo
 
 codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}`
 
+codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`)
+
 codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
 
 codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
diff --git a/compiler/rustc_error_messages/locales/en-US/errors.ftl b/compiler/rustc_error_messages/locales/en-US/errors.ftl
new file mode 100644
index 00000000000..429bdd2777f
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/errors.ftl
@@ -0,0 +1,13 @@
+errors_target_invalid_address_space = invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
+
+errors_target_invalid_bits = invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
+
+errors_target_missing_alignment = missing alignment for `{$cause}` in "data-layout"
+
+errors_target_invalid_alignment = invalid alignment for `{$cause}` in "data-layout": {$err}
+
+errors_target_inconsistent_architecture = inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}`
+
+errors_target_inconsistent_pointer_width = inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}`
+
+errors_target_invalid_bits_size = {$err}
diff --git a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
index c6a4ff6f0e0..74088f4dfbe 100644
--- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
@@ -93,7 +93,7 @@ hir_analysis_expected_default_return_type = expected `()` because of default ret
 hir_analysis_expected_return_type = expected `{$expected}` because of return type
 
 hir_analysis_unconstrained_opaque_type = unconstrained opaque type
-    .note = `{$name}` must be used in combination with a concrete type within the same module
+    .note = `{$name}` must be used in combination with a concrete type within the same {$what}
 
 hir_analysis_missing_type_params =
     the type {$parameterCount ->
@@ -133,3 +133,20 @@ hir_analysis_extern_crate_not_idiomatic =
     .suggestion = convert it to a `{$msg_code}`
 
 hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+
+hir_analysis_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
+
+hir_analysis_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
+
+hir_analysis_const_impl_for_non_const_trait =
+    const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
+    .suggestion = mark `{$trait_name}` as const
+    .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+    .adding = adding a non-const method body in the future would be a breaking change
+
+hir_analysis_const_bound_for_non_const_trait =
+    ~const can only be applied to `#[const_trait]` traits
+
+hir_analysis_self_in_impl_self =
+    `Self` is not valid in the self type of an impl block
+    .note = replace `Self` with a different type
diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl
index 65371a28591..18b3408b06a 100644
--- a/compiler/rustc_error_messages/locales/en-US/infer.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl
@@ -164,7 +164,9 @@ infer_region_explanation = {$pref_kind ->
 }
 
 infer_mismatched_static_lifetime = incompatible lifetime on type
-infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement
+infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement
 infer_msl_introduces_static = introduces a `'static` lifetime requirement
 infer_msl_unmet_req = because this has an unmet lifetime requirement
 infer_msl_trait_note = this has an implicit `'static` lifetime requirement
diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl
index d27100c56af..c292ae9b32a 100644
--- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl
@@ -150,12 +150,28 @@ metadata_no_multiple_global_alloc =
 metadata_prev_global_alloc =
     previous global allocator defined here
 
+metadata_no_multiple_alloc_error_handler =
+    cannot define multiple allocation error handlers
+    .label = cannot define a new allocation error handler
+
+metadata_prev_alloc_error_handler =
+    previous allocation error handler defined here
+
 metadata_conflicting_global_alloc =
     the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
 
+metadata_conflicting_alloc_error_handler =
+    the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name}
+
 metadata_global_alloc_required =
     no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
 
+metadata_alloc_func_required =
+    `#[alloc_error_handler]` function required, but not found
+
+metadata_missing_alloc_error_handler =
+    use `#![feature(default_alloc_error_handler)]` for a default error handler
+
 metadata_no_transitive_needs_dep =
     the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}`
 
@@ -165,6 +181,8 @@ metadata_failed_write_error =
 metadata_missing_native_library =
     could not find native static library `{$libname}`, perhaps an -L flag is missing?
 
+metadata_only_provide_library_name = only provide the library name `{$suggested_name}`, not the full filename
+
 metadata_failed_create_tempdir =
     couldn't create a temp dir: {$err}
 
diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl
index b9e4499d47f..81d8e8a473b 100644
--- a/compiler/rustc_error_messages/locales/en-US/middle.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl
@@ -27,3 +27,7 @@ middle_values_too_big =
 
 middle_cannot_be_normalized =
     unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
+
+middle_strict_coherence_needs_negative_coherence =
+    to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
+    .label = due to this attribute
diff --git a/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl b/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl
index 42c84fdd2d1..48ddb54b79e 100644
--- a/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl
@@ -21,6 +21,3 @@ monomorphize_large_assignments =
     moving {$size} bytes
     .label = value moved from here
     .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
-
-monomorphize_requires_lang_item =
-    requires `{$lang_item}` lang_item
diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 1f1c9c29d66..bc5bfe2a244 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -145,6 +145,9 @@ passes_doc_test_takes_list =
 passes_doc_primitive =
     `doc(primitive)` should never have been stable
 
+passes_doc_cfg_hide_takes_list =
+    `#[doc(cfg_hide(...)]` takes a list of attributes
+
 passes_doc_test_unknown_any =
     unknown `doc` attribute `{$path}`
 
@@ -364,12 +367,6 @@ passes_unknown_external_lang_item =
 passes_missing_panic_handler =
     `#[panic_handler]` function required, but not found
 
-passes_alloc_func_required =
-    `#[alloc_error_handler]` function required, but not found
-
-passes_missing_alloc_error_handler =
-    use `#![feature(default_alloc_error_handler)]` for a default error handler
-
 passes_missing_lang_item =
     language item required, but not found: `{$name}`
     .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library
diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl
index 3ea9429a23a..e2277923072 100644
--- a/compiler/rustc_error_messages/locales/en-US/session.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/session.ftl
@@ -39,20 +39,6 @@ session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination`
 
 session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
 
-session_target_invalid_address_space = invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
-
-session_target_invalid_bits = invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
-
-session_target_missing_alignment = missing alignment for `{$cause}` in "data-layout"
-
-session_target_invalid_alignment = invalid alignment for `{$cause}` in "data-layout": {$err}
-
-session_target_inconsistent_architecture = inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}`
-
-session_target_inconsistent_pointer_width = inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}`
-
-session_target_invalid_bits_size = {$err}
-
 session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored
 
 session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform
@@ -68,3 +54,7 @@ session_crate_name_empty = crate name must not be empty
 session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}`
 
 session_expr_parentheses_needed = parentheses are required to parse this as an expression
+
+session_skipping_const_checks = skipping const checks
+session_unleashed_feature_help_named = skipping check for `{$gate}` feature
+session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index a6024044ad8..9465051dd10 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -46,6 +46,7 @@ fluent_messages! {
     compiletest => "../locales/en-US/compiletest.ftl",
     const_eval => "../locales/en-US/const_eval.ftl",
     driver => "../locales/en-US/driver.ftl",
+    errors => "../locales/en-US/errors.ftl",
     expand => "../locales/en-US/expand.ftl",
     hir_analysis => "../locales/en-US/hir_analysis.ftl",
     infer => "../locales/en-US/infer.ftl",
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 3e0840caaa6..45c017df918 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -3,21 +3,16 @@ use crate::{
     CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, MultiSpan,
     SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
 };
-use rustc_ast as ast;
-use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_error_messages::FluentValue;
-use rustc_hir as hir;
 use rustc_lint_defs::{Applicability, LintExpectationId};
 use rustc_span::edition::LATEST_STABLE_EDITION;
-use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
-use rustc_span::{edition::Edition, Span, DUMMY_SP};
-use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
+use rustc_span::symbol::Symbol;
+use rustc_span::{Span, DUMMY_SP};
 use std::borrow::Cow;
 use std::fmt;
 use std::hash::{Hash, Hasher};
-use std::num::ParseIntError;
-use std::path::{Path, PathBuf};
+use std::panic::Location;
 
 /// Error type for `Diagnostic`'s `suggestions` field, indicating that
 /// `.disable_suggestions()` was called on the `Diagnostic`.
@@ -49,119 +44,6 @@ pub trait IntoDiagnosticArg {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
 }
 
-pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display);
-
-impl IntoDiagnosticArg for DiagnosticArgFromDisplay<'_> {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        self.0.to_string().into_diagnostic_arg()
-    }
-}
-
-impl<'a> From<&'a dyn fmt::Display> for DiagnosticArgFromDisplay<'a> {
-    fn from(t: &'a dyn fmt::Display) -> Self {
-        DiagnosticArgFromDisplay(t)
-    }
-}
-
-impl<'a, T: fmt::Display> From<&'a T> for DiagnosticArgFromDisplay<'a> {
-    fn from(t: &'a T) -> Self {
-        DiagnosticArgFromDisplay(t)
-    }
-}
-
-macro_rules! into_diagnostic_arg_using_display {
-    ($( $ty:ty ),+ $(,)?) => {
-        $(
-            impl IntoDiagnosticArg for $ty {
-                fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-                    self.to_string().into_diagnostic_arg()
-                }
-            }
-        )+
-    }
-}
-
-into_diagnostic_arg_using_display!(
-    i8,
-    u8,
-    i16,
-    u16,
-    i32,
-    u32,
-    i64,
-    u64,
-    i128,
-    u128,
-    std::io::Error,
-    std::num::NonZeroU32,
-    hir::Target,
-    Edition,
-    Ident,
-    MacroRulesNormalizedIdent,
-    ParseIntError,
-    StackProtector,
-    &TargetTriple,
-    SplitDebuginfo
-);
-
-impl IntoDiagnosticArg for bool {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        if self {
-            DiagnosticArgValue::Str(Cow::Borrowed("true"))
-        } else {
-            DiagnosticArgValue::Str(Cow::Borrowed("false"))
-        }
-    }
-}
-
-impl IntoDiagnosticArg for char {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self)))
-    }
-}
-
-impl IntoDiagnosticArg for Symbol {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        self.to_ident_string().into_diagnostic_arg()
-    }
-}
-
-impl<'a> IntoDiagnosticArg for &'a str {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        self.to_string().into_diagnostic_arg()
-    }
-}
-
-impl IntoDiagnosticArg for String {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Str(Cow::Owned(self))
-    }
-}
-
-impl<'a> IntoDiagnosticArg for &'a Path {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Str(Cow::Owned(self.display().to_string()))
-    }
-}
-
-impl IntoDiagnosticArg for PathBuf {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Str(Cow::Owned(self.display().to_string()))
-    }
-}
-
-impl IntoDiagnosticArg for usize {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Number(self)
-    }
-}
-
-impl IntoDiagnosticArg for PanicStrategy {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string()))
-    }
-}
-
 impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
     fn into(self) -> FluentValue<'source> {
         match self {
@@ -171,34 +53,6 @@ impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
     }
 }
 
-impl IntoDiagnosticArg for hir::ConstContext {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Str(Cow::Borrowed(match self {
-            hir::ConstContext::ConstFn => "constant function",
-            hir::ConstContext::Static(_) => "static",
-            hir::ConstContext::Const => "constant",
-        }))
-    }
-}
-
-impl IntoDiagnosticArg for ast::Path {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(&self)))
-    }
-}
-
-impl IntoDiagnosticArg for ast::token::Token {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Str(pprust::token_to_string(&self))
-    }
-}
-
-impl IntoDiagnosticArg for ast::token::TokenKind {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Str(pprust::token_kind_to_string(&self))
-    }
-}
-
 /// Trait implemented by error types. This should not be implemented manually. Instead, use
 /// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
 #[cfg_attr(bootstrap, rustc_diagnostic_item = "AddSubdiagnostic")]
@@ -254,6 +108,31 @@ pub struct Diagnostic {
     /// If diagnostic is from Lint, custom hash function ignores notes
     /// otherwise hash is based on the all the fields
     pub is_lint: bool,
+
+    /// With `-Ztrack_diagnostics` enabled,
+    /// we print where in rustc this error was emitted.
+    pub emitted_at: DiagnosticLocation,
+}
+
+#[derive(Clone, Debug, Encodable, Decodable)]
+pub struct DiagnosticLocation {
+    file: Cow<'static, str>,
+    line: u32,
+    col: u32,
+}
+
+impl DiagnosticLocation {
+    #[track_caller]
+    fn caller() -> Self {
+        let loc = Location::caller();
+        DiagnosticLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }
+    }
+}
+
+impl fmt::Display for DiagnosticLocation {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}:{}:{}", self.file, self.line, self.col)
+    }
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
@@ -320,10 +199,12 @@ impl StringPart {
 }
 
 impl Diagnostic {
+    #[track_caller]
     pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self {
         Diagnostic::new_with_code(level, None, message)
     }
 
+    #[track_caller]
     pub fn new_with_code<M: Into<DiagnosticMessage>>(
         level: Level,
         code: Option<DiagnosticId>,
@@ -339,6 +220,7 @@ impl Diagnostic {
             args: Default::default(),
             sort_span: DUMMY_SP,
             is_lint: false,
+            emitted_at: DiagnosticLocation::caller(),
         }
     }
 
@@ -714,6 +596,11 @@ impl Diagnostic {
         style: SuggestionStyle,
     ) -> &mut Self {
         assert!(!suggestion.is_empty());
+        debug_assert!(
+            !(suggestion.iter().any(|(sp, text)| sp.is_empty() && text.is_empty())),
+            "Span must not be empty and have no suggestion"
+        );
+
         self.push_suggestion(CodeSuggestion {
             substitutions: vec![Substitution {
                 parts: suggestion
@@ -791,6 +678,10 @@ impl Diagnostic {
         applicability: Applicability,
         style: SuggestionStyle,
     ) -> &mut Self {
+        debug_assert!(
+            !(sp.is_empty() && suggestion.to_string().is_empty()),
+            "Span must not be empty and have no suggestion"
+        );
         self.push_suggestion(CodeSuggestion {
             substitutions: vec![Substitution {
                 parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
@@ -829,8 +720,32 @@ impl Diagnostic {
         suggestions: impl Iterator<Item = String>,
         applicability: Applicability,
     ) -> &mut Self {
+        self.span_suggestions_with_style(
+            sp,
+            msg,
+            suggestions,
+            applicability,
+            SuggestionStyle::ShowCode,
+        )
+    }
+
+    /// [`Diagnostic::span_suggestions()`] but you can set the [`SuggestionStyle`].
+    pub fn span_suggestions_with_style(
+        &mut self,
+        sp: Span,
+        msg: impl Into<SubdiagnosticMessage>,
+        suggestions: impl Iterator<Item = String>,
+        applicability: Applicability,
+        style: SuggestionStyle,
+    ) -> &mut Self {
         let mut suggestions: Vec<_> = suggestions.collect();
         suggestions.sort();
+
+        debug_assert!(
+            !(sp.is_empty() && suggestions.iter().any(|suggestion| suggestion.is_empty())),
+            "Span must not be empty and have no suggestion"
+        );
+
         let substitutions = suggestions
             .into_iter()
             .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
@@ -838,22 +753,33 @@ impl Diagnostic {
         self.push_suggestion(CodeSuggestion {
             substitutions,
             msg: self.subdiagnostic_message_to_diagnostic_message(msg),
-            style: SuggestionStyle::ShowCode,
+            style,
             applicability,
         });
         self
     }
 
-    /// Prints out a message with multiple suggested edits of the code.
-    /// See also [`Diagnostic::span_suggestion()`].
+    /// Prints out a message with multiple suggested edits of the code, where each edit consists of
+    /// multiple parts.
+    /// See also [`Diagnostic::multipart_suggestion()`].
     pub fn multipart_suggestions(
         &mut self,
         msg: impl Into<SubdiagnosticMessage>,
         suggestions: impl Iterator<Item = Vec<(Span, String)>>,
         applicability: Applicability,
     ) -> &mut Self {
+        let suggestions: Vec<_> = suggestions.collect();
+        debug_assert!(
+            !(suggestions
+                .iter()
+                .flat_map(|suggs| suggs)
+                .any(|(sp, suggestion)| sp.is_empty() && suggestion.is_empty())),
+            "Span must not be empty and have no suggestion"
+        );
+
         self.push_suggestion(CodeSuggestion {
             substitutions: suggestions
+                .into_iter()
                 .map(|sugg| Substitution {
                     parts: sugg
                         .into_iter()
@@ -867,6 +793,7 @@ impl Diagnostic {
         });
         self
     }
+
     /// Prints out a message with a suggested edit of the code. If the suggestion is presented
     /// inline, it will only show the message and not the suggestion.
     ///
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 9b41234dcfb..ecf8570e81f 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -133,6 +133,7 @@ mod sealed_level_is_error {
 impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> {
     /// Convenience function for internal use, clients should use one of the
     /// `struct_*` methods on [`Handler`].
+    #[track_caller]
     pub(crate) fn new_guaranteeing_error<M: Into<DiagnosticMessage>, const L: Level>(
         handler: &'a Handler,
         message: M,
@@ -196,6 +197,7 @@ impl EmissionGuarantee for ErrorGuaranteed {
         }
     }
 
+    #[track_caller]
     fn make_diagnostic_builder(
         handler: &Handler,
         msg: impl Into<DiagnosticMessage>,
@@ -209,6 +211,7 @@ impl EmissionGuarantee for ErrorGuaranteed {
 impl<'a> DiagnosticBuilder<'a, ()> {
     /// Convenience function for internal use, clients should use one of the
     /// `struct_*` methods on [`Handler`].
+    #[track_caller]
     pub(crate) fn new<M: Into<DiagnosticMessage>>(
         handler: &'a Handler,
         level: Level,
@@ -220,6 +223,7 @@ impl<'a> DiagnosticBuilder<'a, ()> {
 
     /// Creates a new `DiagnosticBuilder` with an already constructed
     /// diagnostic.
+    #[track_caller]
     pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
         debug!("Created new diagnostic");
         Self {
@@ -308,6 +312,7 @@ impl EmissionGuarantee for Noted {
 impl<'a> DiagnosticBuilder<'a, !> {
     /// Convenience function for internal use, clients should use one of the
     /// `struct_*` methods on [`Handler`].
+    #[track_caller]
     pub(crate) fn new_fatal(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
         let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message);
         Self::new_diagnostic_fatal(handler, diagnostic)
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
new file mode 100644
index 00000000000..7640b2919f7
--- /dev/null
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -0,0 +1,222 @@
+use crate::{
+    fluent, DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg,
+};
+use rustc_ast as ast;
+use rustc_ast_pretty::pprust;
+use rustc_hir as hir;
+use rustc_lint_defs::Level;
+use rustc_span::edition::Edition;
+use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
+use rustc_target::abi::TargetDataLayoutErrors;
+use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
+use std::borrow::Cow;
+use std::fmt;
+use std::num::ParseIntError;
+use std::path::{Path, PathBuf};
+
+pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display);
+
+impl IntoDiagnosticArg for DiagnosticArgFromDisplay<'_> {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        self.0.to_string().into_diagnostic_arg()
+    }
+}
+
+impl<'a> From<&'a dyn fmt::Display> for DiagnosticArgFromDisplay<'a> {
+    fn from(t: &'a dyn fmt::Display) -> Self {
+        DiagnosticArgFromDisplay(t)
+    }
+}
+
+impl<'a, T: fmt::Display> From<&'a T> for DiagnosticArgFromDisplay<'a> {
+    fn from(t: &'a T) -> Self {
+        DiagnosticArgFromDisplay(t)
+    }
+}
+
+macro_rules! into_diagnostic_arg_using_display {
+    ($( $ty:ty ),+ $(,)?) => {
+        $(
+            impl IntoDiagnosticArg for $ty {
+                fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+                    self.to_string().into_diagnostic_arg()
+                }
+            }
+        )+
+    }
+}
+
+into_diagnostic_arg_using_display!(
+    i8,
+    u8,
+    i16,
+    u16,
+    i32,
+    u32,
+    i64,
+    u64,
+    i128,
+    u128,
+    std::io::Error,
+    std::num::NonZeroU32,
+    hir::Target,
+    Edition,
+    Ident,
+    MacroRulesNormalizedIdent,
+    ParseIntError,
+    StackProtector,
+    &TargetTriple,
+    SplitDebuginfo
+);
+
+impl IntoDiagnosticArg for bool {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        if self {
+            DiagnosticArgValue::Str(Cow::Borrowed("true"))
+        } else {
+            DiagnosticArgValue::Str(Cow::Borrowed("false"))
+        }
+    }
+}
+
+impl IntoDiagnosticArg for char {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self)))
+    }
+}
+
+impl IntoDiagnosticArg for Symbol {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        self.to_ident_string().into_diagnostic_arg()
+    }
+}
+
+impl<'a> IntoDiagnosticArg for &'a str {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        self.to_string().into_diagnostic_arg()
+    }
+}
+
+impl IntoDiagnosticArg for String {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self))
+    }
+}
+
+impl<'a> IntoDiagnosticArg for &'a Path {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.display().to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for PathBuf {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.display().to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for usize {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Number(self)
+    }
+}
+
+impl IntoDiagnosticArg for PanicStrategy {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for hir::ConstContext {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Borrowed(match self {
+            hir::ConstContext::ConstFn => "constant function",
+            hir::ConstContext::Static(_) => "static",
+            hir::ConstContext::Const => "constant",
+        }))
+    }
+}
+
+impl IntoDiagnosticArg for ast::Path {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(&self)))
+    }
+}
+
+impl IntoDiagnosticArg for ast::token::Token {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(pprust::token_to_string(&self))
+    }
+}
+
+impl IntoDiagnosticArg for ast::token::TokenKind {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(pprust::token_kind_to_string(&self))
+    }
+}
+
+impl IntoDiagnosticArg for Level {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Borrowed(match self {
+            Level::Allow => "-A",
+            Level::Warn => "-W",
+            Level::ForceWarn(_) => "--force-warn",
+            Level::Deny => "-D",
+            Level::Forbid => "-F",
+            Level::Expect(_) => {
+                unreachable!("lints with the level of `expect` should not run this code");
+            }
+        }))
+    }
+}
+
+impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
+    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
+        let mut diag;
+        match self {
+            TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
+                diag = handler.struct_fatal(fluent::errors_target_invalid_address_space);
+                diag.set_arg("addr_space", addr_space);
+                diag.set_arg("cause", cause);
+                diag.set_arg("err", err);
+                diag
+            }
+            TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
+                diag = handler.struct_fatal(fluent::errors_target_invalid_bits);
+                diag.set_arg("kind", kind);
+                diag.set_arg("bit", bit);
+                diag.set_arg("cause", cause);
+                diag.set_arg("err", err);
+                diag
+            }
+            TargetDataLayoutErrors::MissingAlignment { cause } => {
+                diag = handler.struct_fatal(fluent::errors_target_missing_alignment);
+                diag.set_arg("cause", cause);
+                diag
+            }
+            TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
+                diag = handler.struct_fatal(fluent::errors_target_invalid_alignment);
+                diag.set_arg("cause", cause);
+                diag.set_arg("err", err);
+                diag
+            }
+            TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
+                diag = handler.struct_fatal(fluent::errors_target_inconsistent_architecture);
+                diag.set_arg("dl", dl);
+                diag.set_arg("target", target);
+                diag
+            }
+            TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
+                diag = handler.struct_fatal(fluent::errors_target_inconsistent_pointer_width);
+                diag.set_arg("pointer_size", pointer_size);
+                diag.set_arg("target", target);
+                diag
+            }
+            TargetDataLayoutErrors::InvalidBitsSize { err } => {
+                diag = handler.struct_fatal(fluent::errors_target_invalid_bits_size);
+                diag.set_arg("err", err);
+                diag
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index cd6413bc3ec..b7b8fe3f25a 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -16,10 +16,10 @@ use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Styl
 use crate::styled_buffer::StyledBuffer;
 use crate::translation::{to_fluent_args, Translate};
 use crate::{
-    CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler,
-    LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
+    diagnostic::DiagnosticLocation, CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage,
+    FluentBundle, Handler, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic,
+    SubstitutionHighlight, SuggestionStyle,
 };
-
 use rustc_lint_defs::pluralize;
 
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
@@ -64,6 +64,7 @@ impl HumanReadableErrorType {
         teach: bool,
         diagnostic_width: Option<usize>,
         macro_backtrace: bool,
+        track_diagnostics: bool,
     ) -> EmitterWriter {
         let (short, color_config) = self.unzip();
         let color = color_config.suggests_using_colors();
@@ -77,6 +78,7 @@ impl HumanReadableErrorType {
             color,
             diagnostic_width,
             macro_backtrace,
+            track_diagnostics,
         )
     }
 }
@@ -557,6 +559,7 @@ impl Emitter for EmitterWriter {
             &primary_span,
             &children,
             &suggestions,
+            self.track_diagnostics.then_some(&diag.emitted_at),
         );
     }
 
@@ -650,6 +653,7 @@ pub struct EmitterWriter {
     diagnostic_width: Option<usize>,
 
     macro_backtrace: bool,
+    track_diagnostics: bool,
 }
 
 #[derive(Debug)]
@@ -669,6 +673,7 @@ impl EmitterWriter {
         teach: bool,
         diagnostic_width: Option<usize>,
         macro_backtrace: bool,
+        track_diagnostics: bool,
     ) -> EmitterWriter {
         let dst = Destination::from_stderr(color_config);
         EmitterWriter {
@@ -681,6 +686,7 @@ impl EmitterWriter {
             ui_testing: false,
             diagnostic_width,
             macro_backtrace,
+            track_diagnostics,
         }
     }
 
@@ -694,6 +700,7 @@ impl EmitterWriter {
         colored: bool,
         diagnostic_width: Option<usize>,
         macro_backtrace: bool,
+        track_diagnostics: bool,
     ) -> EmitterWriter {
         EmitterWriter {
             dst: Raw(dst, colored),
@@ -705,6 +712,7 @@ impl EmitterWriter {
             ui_testing: false,
             diagnostic_width,
             macro_backtrace,
+            track_diagnostics,
         }
     }
 
@@ -1327,6 +1335,7 @@ impl EmitterWriter {
         level: &Level,
         max_line_num_len: usize,
         is_secondary: bool,
+        emitted_at: Option<&DiagnosticLocation>,
     ) -> io::Result<()> {
         let mut buffer = StyledBuffer::new();
 
@@ -1377,7 +1386,6 @@ impl EmitterWriter {
                 }
             }
         }
-
         let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp);
 
         // Make sure our primary file comes first
@@ -1653,6 +1661,12 @@ impl EmitterWriter {
             }
         }
 
+        if let Some(tracked) = emitted_at {
+            let track = format!("-Ztrack-diagnostics: created at {tracked}");
+            let len = buffer.num_lines();
+            buffer.append(len, &track, Style::NoStyle);
+        }
+
         // final step: take our styled buffer, render it, then output it
         emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
 
@@ -1977,6 +1991,7 @@ impl EmitterWriter {
         span: &MultiSpan,
         children: &[SubDiagnostic],
         suggestions: &[CodeSuggestion],
+        emitted_at: Option<&DiagnosticLocation>,
     ) {
         let max_line_num_len = if self.ui_testing {
             ANONYMIZED_LINE_NUM.len()
@@ -1985,7 +2000,16 @@ impl EmitterWriter {
             num_decimal_digits(n)
         };
 
-        match self.emit_message_default(span, message, args, code, level, max_line_num_len, false) {
+        match self.emit_message_default(
+            span,
+            message,
+            args,
+            code,
+            level,
+            max_line_num_len,
+            false,
+            emitted_at,
+        ) {
             Ok(()) => {
                 if !children.is_empty()
                     || suggestions.iter().any(|s| s.style != SuggestionStyle::CompletelyHidden)
@@ -2014,6 +2038,7 @@ impl EmitterWriter {
                             &child.level,
                             max_line_num_len,
                             true,
+                            None,
                         ) {
                             panic!("failed to emit error: {}", err);
                         }
@@ -2030,6 +2055,7 @@ impl EmitterWriter {
                                 &Level::Help,
                                 max_line_num_len,
                                 true,
+                                None,
                             ) {
                                 panic!("failed to emit error: {}", e);
                             }
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 4cc7be47fc2..c4498eafa4e 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -45,6 +45,7 @@ pub struct JsonEmitter {
     json_rendered: HumanReadableErrorType,
     diagnostic_width: Option<usize>,
     macro_backtrace: bool,
+    track_diagnostics: bool,
 }
 
 impl JsonEmitter {
@@ -57,6 +58,7 @@ impl JsonEmitter {
         json_rendered: HumanReadableErrorType,
         diagnostic_width: Option<usize>,
         macro_backtrace: bool,
+        track_diagnostics: bool,
     ) -> JsonEmitter {
         JsonEmitter {
             dst: Box::new(io::BufWriter::new(io::stderr())),
@@ -69,6 +71,7 @@ impl JsonEmitter {
             json_rendered,
             diagnostic_width,
             macro_backtrace,
+            track_diagnostics,
         }
     }
 
@@ -79,6 +82,7 @@ impl JsonEmitter {
         fallback_bundle: LazyFallbackBundle,
         diagnostic_width: Option<usize>,
         macro_backtrace: bool,
+        track_diagnostics: bool,
     ) -> JsonEmitter {
         let file_path_mapping = FilePathMapping::empty();
         JsonEmitter::stderr(
@@ -90,6 +94,7 @@ impl JsonEmitter {
             json_rendered,
             diagnostic_width,
             macro_backtrace,
+            track_diagnostics,
         )
     }
 
@@ -103,6 +108,7 @@ impl JsonEmitter {
         json_rendered: HumanReadableErrorType,
         diagnostic_width: Option<usize>,
         macro_backtrace: bool,
+        track_diagnostics: bool,
     ) -> JsonEmitter {
         JsonEmitter {
             dst,
@@ -115,6 +121,7 @@ impl JsonEmitter {
             json_rendered,
             diagnostic_width,
             macro_backtrace,
+            track_diagnostics,
         }
     }
 
@@ -350,6 +357,7 @@ impl Diagnostic {
                 false,
                 je.diagnostic_width,
                 je.macro_backtrace,
+                je.track_diagnostics,
             )
             .ui_testing(je.ui_testing)
             .emit_diagnostic(diag);
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index d940d14e1db..f131468971b 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -59,6 +59,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
             HumanReadableErrorType::Short(ColorConfig::Never),
             None,
             false,
+            false,
         );
 
         let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1));
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index b16c54e0aac..f390495b53d 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -51,6 +51,7 @@ use termcolor::{Color, ColorSpec};
 pub mod annotate_snippet_emitter_writer;
 mod diagnostic;
 mod diagnostic_builder;
+mod diagnostic_impls;
 pub mod emitter;
 pub mod json;
 mod lock;
@@ -371,10 +372,11 @@ impl fmt::Display for ExplicitBug {
 impl error::Error for ExplicitBug {}
 
 pub use diagnostic::{
-    AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay,
-    DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
+    AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
+    DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
 };
 pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
+pub use diagnostic_impls::DiagnosticArgFromDisplay;
 use std::backtrace::Backtrace;
 
 /// A handler deals with errors and other compiler output.
@@ -461,6 +463,9 @@ pub enum StashKey {
     UnderscoreForArrayLengths,
     EarlySyntaxWarning,
     CallIntoMethod,
+    /// When an invalid lifetime e.g. `'2` should be reinterpreted
+    /// as a char literal in the parser
+    LifetimeIsChar,
 }
 
 fn default_track_diagnostic(_: &Diagnostic) {}
@@ -487,6 +492,8 @@ pub struct HandlerFlags {
     pub macro_backtrace: bool,
     /// If true, identical diagnostics are reported only once.
     pub deduplicate_diagnostics: bool,
+    /// Track where errors are created. Enabled with `-Ztrack-diagnostics`.
+    pub track_diagnostics: bool,
 }
 
 impl Drop for HandlerInner {
@@ -554,6 +561,7 @@ impl Handler {
             false,
             None,
             flags.macro_backtrace,
+            flags.track_diagnostics,
         ));
         Self::with_emitter_and_flags(emitter, flags)
     }
@@ -659,6 +667,7 @@ impl Handler {
 
     /// Construct a builder with the `msg` at the level appropriate for the specific `EmissionGuarantee`.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_diagnostic<G: EmissionGuarantee>(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -672,6 +681,7 @@ impl Handler {
     /// * `can_emit_warnings` is `true`
     /// * `is_force_warn` was set in `DiagnosticId::Lint`
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_warn(
         &self,
         span: impl Into<MultiSpan>,
@@ -688,6 +698,7 @@ impl Handler {
     /// Attempting to `.emit()` the builder will only emit if either:
     /// * `can_emit_warnings` is `true`
     /// * `is_force_warn` was set in `DiagnosticId::Lint`
+    #[track_caller]
     pub fn struct_span_warn_with_expectation(
         &self,
         span: impl Into<MultiSpan>,
@@ -701,6 +712,7 @@ impl Handler {
 
     /// Construct a builder at the `Allow` level at the given `span` and with the `msg`.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_allow(
         &self,
         span: impl Into<MultiSpan>,
@@ -714,6 +726,7 @@ impl Handler {
     /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
     /// Also include a code.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_warn_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -731,6 +744,7 @@ impl Handler {
     /// * `can_emit_warnings` is `true`
     /// * `is_force_warn` was set in `DiagnosticId::Lint`
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         DiagnosticBuilder::new(self, Level::Warning(None), msg)
     }
@@ -741,6 +755,7 @@ impl Handler {
     /// Attempting to `.emit()` the builder will only emit if either:
     /// * `can_emit_warnings` is `true`
     /// * `is_force_warn` was set in `DiagnosticId::Lint`
+    #[track_caller]
     pub fn struct_warn_with_expectation(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -751,12 +766,14 @@ impl Handler {
 
     /// Construct a builder at the `Allow` level with the `msg`.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         DiagnosticBuilder::new(self, Level::Allow, msg)
     }
 
     /// Construct a builder at the `Expect` level with the `msg`.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_expect(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -767,6 +784,7 @@ impl Handler {
 
     /// Construct a builder at the `Error` level at the given `span` and with the `msg`.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_err(
         &self,
         span: impl Into<MultiSpan>,
@@ -779,6 +797,7 @@ impl Handler {
 
     /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_err_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -793,6 +812,7 @@ impl Handler {
     /// Construct a builder at the `Error` level with the `msg`.
     // FIXME: This method should be removed (every error should have an associated error code).
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -802,12 +822,14 @@ impl Handler {
 
     /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
     #[doc(hidden)]
+    #[track_caller]
     pub fn struct_err_lint(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         DiagnosticBuilder::new(self, Level::Error { lint: true }, msg)
     }
 
     /// Construct a builder at the `Error` level with the `msg` and the `code`.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_err_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -820,6 +842,7 @@ impl Handler {
 
     /// Construct a builder at the `Warn` level with the `msg` and the `code`.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_warn_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -832,6 +855,7 @@ impl Handler {
 
     /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_fatal(
         &self,
         span: impl Into<MultiSpan>,
@@ -844,6 +868,7 @@ impl Handler {
 
     /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_fatal_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -857,6 +882,7 @@ impl Handler {
 
     /// Construct a builder at the `Error` level with the `msg`.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
         DiagnosticBuilder::new_fatal(self, msg)
     }
@@ -869,6 +895,7 @@ impl Handler {
 
     /// Construct a builder at the `Note` level with the `msg`.
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_note_without_error(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -877,12 +904,14 @@ impl Handler {
     }
 
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
         self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
         FatalError.raise()
     }
 
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn span_fatal_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -894,6 +923,7 @@ impl Handler {
     }
 
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn span_err(
         &self,
         span: impl Into<MultiSpan>,
@@ -903,6 +933,7 @@ impl Handler {
     }
 
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn span_err_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -916,11 +947,13 @@ impl Handler {
     }
 
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
         self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span);
     }
 
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn span_warn_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -949,10 +982,12 @@ impl Handler {
         self.inner.borrow_mut().delay_good_path_bug(msg)
     }
 
+    #[track_caller]
     pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
         self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
     }
 
+    #[track_caller]
     pub fn span_note_without_error(
         &self,
         span: impl Into<MultiSpan>,
@@ -961,6 +996,7 @@ impl Handler {
         self.emit_diag_at_span(Diagnostic::new(Note, msg), span);
     }
 
+    #[track_caller]
     pub fn span_note_diag(
         &self,
         span: Span,
@@ -1447,6 +1483,7 @@ impl HandlerInner {
         }
     }
 
+    #[track_caller]
     fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
         self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
         panic::panic_any(ExplicitBug);
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index cd8a525e062..c8de60ccb89 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -22,7 +22,7 @@ use rustc_span::edition::Edition;
 use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{FileName, Span, DUMMY_SP};
+use rustc_span::{BytePos, FileName, RealFileName, Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 
 use std::default::Default;
@@ -1228,8 +1228,9 @@ pub fn expr_to_spanned_string<'a>(
             ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)),
             ast::LitKind::ByteStr(_) => {
                 let mut err = cx.struct_span_err(l.span, err_msg);
+                let span = expr.span.shrink_to_lo();
                 err.span_suggestion(
-                    expr.span.shrink_to_lo(),
+                    span.with_hi(span.lo() + BytePos(1)),
                     "consider removing the leading `b`",
                     "",
                     Applicability::MaybeIncorrect,
@@ -1422,16 +1423,40 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool {
         if let ast::ItemKind::Enum(enum_def, _) = &item.kind {
             if let [variant] = &*enum_def.variants {
                 if variant.ident.name == sym::Input {
-                    sess.buffer_lint_with_diagnostic(
-                        &PROC_MACRO_BACK_COMPAT,
-                        item.ident.span,
-                        ast::CRATE_NODE_ID,
-                        "using `procedural-masquerade` crate",
-                        BuiltinLintDiagnostics::ProcMacroBackCompat(
-                        "The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. \
-                        Versions of this crate below 0.1.7 will eventually stop compiling.".to_string())
-                    );
-                    return true;
+                    let filename = sess.source_map().span_to_filename(item.ident.span);
+                    if let FileName::Real(RealFileName::LocalPath(path)) = filename {
+                        if let Some(c) = path
+                            .components()
+                            .flat_map(|c| c.as_os_str().to_str())
+                            .find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental"))
+                        {
+                            let crate_matches = if c.starts_with("allsorts-rental") {
+                                true
+                            } else {
+                                let mut version = c.trim_start_matches("rental-").split(".");
+                                version.next() == Some("0")
+                                    && version.next() == Some("5")
+                                    && version
+                                        .next()
+                                        .and_then(|c| c.parse::<u32>().ok())
+                                        .map_or(false, |v| v < 6)
+                            };
+
+                            if crate_matches {
+                                sess.buffer_lint_with_diagnostic(
+                                        &PROC_MACRO_BACK_COMPAT,
+                                        item.ident.span,
+                                        ast::CRATE_NODE_ID,
+                                        "using an old version of `rental`",
+                                        BuiltinLintDiagnostics::ProcMacroBackCompat(
+                                        "older versions of the `rental` crate will stop compiling in future versions of Rust; \
+                                        please update to `rental` v0.5.6, or switch to one of the `rental` alternatives".to_string()
+                                        )
+                                    );
+                                return true;
+                            }
+                        }
+                    }
                 }
             }
         }
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 8d4e3640748..1d2b1298a68 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -469,6 +469,7 @@ impl<'a> StripUnconfigured<'a> {
     }
 
     /// If attributes are not allowed on expressions, emit an error for `attr`
+    #[instrument(level = "trace", skip(self))]
     pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
         if !self.features.map_or(true, |features| features.stmt_expr_attributes) {
             let mut err = feature_err(
@@ -486,9 +487,12 @@ impl<'a> StripUnconfigured<'a> {
         }
     }
 
-    pub fn configure_expr(&self, expr: &mut P<ast::Expr>) {
-        for attr in expr.attrs.iter() {
-            self.maybe_emit_expr_attr_err(attr);
+    #[instrument(level = "trace", skip(self))]
+    pub fn configure_expr(&self, expr: &mut P<ast::Expr>, method_receiver: bool) {
+        if !method_receiver {
+            for attr in expr.attrs.iter() {
+                self.maybe_emit_expr_attr_err(attr);
+            }
         }
 
         // If an expr is valid to cfg away it will have been removed by the
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index bd93f0717f5..d383f4832f6 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -3,28 +3,28 @@ use rustc_span::symbol::MacroRulesNormalizedIdent;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(expand::expr_repeat_no_syntax_vars)]
+#[diag(expand_expr_repeat_no_syntax_vars)]
 pub(crate) struct NoSyntaxVarsExprRepeat {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(expand::must_repeat_once)]
+#[diag(expand_must_repeat_once)]
 pub(crate) struct MustRepeatOnce {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(expand::count_repetition_misplaced)]
+#[diag(expand_count_repetition_misplaced)]
 pub(crate) struct CountRepetitionMisplaced {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(expand::meta_var_expr_unrecognized_var)]
+#[diag(expand_meta_var_expr_unrecognized_var)]
 pub(crate) struct MetaVarExprUnrecognizedVar {
     #[primary_span]
     pub span: Span,
@@ -32,7 +32,7 @@ pub(crate) struct MetaVarExprUnrecognizedVar {
 }
 
 #[derive(Diagnostic)]
-#[diag(expand::var_still_repeating)]
+#[diag(expand_var_still_repeating)]
 pub(crate) struct VarStillRepeating {
     #[primary_span]
     pub span: Span,
@@ -40,7 +40,7 @@ pub(crate) struct VarStillRepeating {
 }
 
 #[derive(Diagnostic)]
-#[diag(expand::meta_var_dif_seq_matchers)]
+#[diag(expand_meta_var_dif_seq_matchers)]
 pub(crate) struct MetaVarsDifSeqMatchers {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index c2add852a06..57713fb3cd6 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -50,6 +50,7 @@ macro_rules! ast_fragments {
         /// Can also serve as an input and intermediate result for macro expansion operations.
         pub enum AstFragment {
             OptExpr(Option<P<ast::Expr>>),
+            MethodReceiverExpr(P<ast::Expr>),
             $($Kind($AstTy),)*
         }
 
@@ -57,6 +58,7 @@ macro_rules! ast_fragments {
         #[derive(Copy, Clone, PartialEq, Eq)]
         pub enum AstFragmentKind {
             OptExpr,
+            MethodReceiverExpr,
             $($Kind,)*
         }
 
@@ -64,6 +66,7 @@ macro_rules! ast_fragments {
             pub fn name(self) -> &'static str {
                 match self {
                     AstFragmentKind::OptExpr => "expression",
+                    AstFragmentKind::MethodReceiverExpr => "expression",
                     $(AstFragmentKind::$Kind => $kind_name,)*
                 }
             }
@@ -72,6 +75,8 @@ macro_rules! ast_fragments {
                 match self {
                     AstFragmentKind::OptExpr =>
                         result.make_expr().map(Some).map(AstFragment::OptExpr),
+                    AstFragmentKind::MethodReceiverExpr =>
+                        result.make_expr().map(AstFragment::MethodReceiverExpr),
                     $(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)*
                 }
             }
@@ -98,6 +103,13 @@ macro_rules! ast_fragments {
                 }
             }
 
+            pub fn make_method_receiver_expr(self) -> P<ast::Expr> {
+                match self {
+                    AstFragment::MethodReceiverExpr(expr) => expr,
+                    _ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
+                }
+            }
+
             $(pub fn $make_ast(self) -> $AstTy {
                 match self {
                     AstFragment::$Kind(ast) => ast,
@@ -120,6 +132,7 @@ macro_rules! ast_fragments {
                             }
                         });
                     }
+                    AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr),
                     $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)*
                     $($(AstFragment::$Kind(ast) =>
                         ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)*
@@ -130,6 +143,7 @@ macro_rules! ast_fragments {
                 match *self {
                     AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
                     AstFragment::OptExpr(None) => {}
+                    AstFragment::MethodReceiverExpr(ref expr) => visitor.visit_method_receiver_expr(expr),
                     $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)*
                     $($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] {
                         visitor.$visit_ast_elt(ast_elt, $($args)*);
@@ -222,6 +236,7 @@ impl AstFragmentKind {
         match self {
             AstFragmentKind::OptExpr
             | AstFragmentKind::Expr
+            | AstFragmentKind::MethodReceiverExpr
             | AstFragmentKind::Stmts
             | AstFragmentKind::Ty
             | AstFragmentKind::Pat => SupportsMacroExpansion::Yes { supports_inner_attrs: false },
@@ -285,6 +300,9 @@ impl AstFragmentKind {
             AstFragmentKind::Expr => AstFragment::Expr(
                 items.next().expect("expected exactly one expression").expect_expr(),
             ),
+            AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(
+                items.next().expect("expected exactly one expression").expect_expr(),
+            ),
             AstFragmentKind::OptExpr => {
                 AstFragment::OptExpr(items.next().map(Annotatable::expect_expr))
             }
@@ -327,7 +345,7 @@ impl InvocationKind {
     fn placeholder_visibility(&self) -> Option<ast::Visibility> {
         // HACK: For unnamed fields placeholders should have the same visibility as the actual
         // fields because for tuple structs/variants resolve determines visibilities of their
-        // constructor using these field visibilities before attributes on them are are expanded.
+        // constructor using these field visibilities before attributes on them are expanded.
         // The assumption is that the attribute expansion cannot change field visibilities,
         // and it holds because only inert attributes are supported in this position.
         match self {
@@ -893,6 +911,7 @@ pub fn parse_ast_fragment<'a>(
             AstFragment::Stmts(stmts)
         }
         AstFragmentKind::Expr => AstFragment::Expr(this.parse_expr()?),
+        AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(this.parse_expr()?),
         AstFragmentKind::OptExpr => {
             if this.token != token::Eof {
                 AstFragment::OptExpr(Some(this.parse_expr()?))
@@ -937,13 +956,12 @@ pub fn ensure_complete_parse<'a>(
             kind_name,
         );
         err.note(&msg);
-        let semi_span = this.sess.source_map().next_point(span);
 
-        let semi_full_span = semi_span.to(this.sess.source_map().next_point(semi_span));
-        match this.sess.source_map().span_to_snippet(semi_full_span) {
+        let semi_span = this.sess.source_map().next_point(span);
+        match this.sess.source_map().span_to_snippet(semi_span) {
             Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => {
                 err.span_suggestion(
-                    semi_span,
+                    span.shrink_to_hi(),
                     "you might be missing a semicolon here",
                     ";",
                     Applicability::MaybeIncorrect,
@@ -1478,6 +1496,42 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> {
     }
 }
 
+/// This struct is a hack to workaround unstable of `stmt_expr_attributes`.
+/// It can be removed once that feature is stabilized.
+struct MethodReceiverTag;
+impl DummyAstNode for MethodReceiverTag {
+    fn dummy() -> MethodReceiverTag {
+        MethodReceiverTag
+    }
+}
+impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag> {
+    type OutputTy = Self;
+    type AttrsTy = ast::AttrVec;
+    const KIND: AstFragmentKind = AstFragmentKind::MethodReceiverExpr;
+    fn descr() -> &'static str {
+        "an expression"
+    }
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::Expr(self.wrapped)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag)
+    }
+    fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+        noop_visit_expr(&mut self.wrapped, visitor)
+    }
+    fn is_mac_call(&self) -> bool {
+        matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
+    }
+    fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
+        let node = self.wrapped.into_inner();
+        match node.kind {
+            ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+            _ => unreachable!(),
+        }
+    }
+}
+
 struct InvocationCollector<'a, 'b> {
     cx: &'a mut ExtCtxt<'b>,
     invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>,
@@ -1841,6 +1895,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         self.visit_node(node)
     }
 
+    fn visit_method_receiver_expr(&mut self, node: &mut P<ast::Expr>) {
+        visit_clobber(node, |node| {
+            let mut wrapper = AstNodeWrapper::new(node, MethodReceiverTag);
+            self.visit_node(&mut wrapper);
+            wrapper.wrapped
+        })
+    }
+
     fn filter_map_expr(&mut self, node: P<ast::Expr>) -> Option<P<ast::Expr>> {
         self.flat_map_node(AstNodeWrapper::new(node, OptExprTag))
     }
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 30aa4f0fa34..f6fe38174f7 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -82,7 +82,7 @@ fn emit_frag_parse_err(
         );
         if !e.span.is_dummy() {
             // early end of macro arm (#52866)
-            e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
+            e.replace_span_with(parser.token.span.shrink_to_hi());
         }
     }
     if e.span.is_dummy() {
@@ -250,6 +250,7 @@ fn expand_macro<'cx>(
     // hacky, but speeds up the `html5ever` benchmark significantly. (Issue
     // 68836 suggests a more comprehensive but more complex change to deal with
     // this situation.)
+    // FIXME(Nilstrieb): Stop recovery from happening on this parser and retry later with recovery if the macro failed to match.
     let parser = parser_from_cx(sess, arg.clone());
 
     // Try each arm's matchers.
@@ -598,12 +599,12 @@ pub fn compile_declarative_macro(
 
 #[derive(Subdiagnostic)]
 enum ExplainDocComment {
-    #[label(expand::explain_doc_comment_inner)]
+    #[label(expand_explain_doc_comment_inner)]
     Inner {
         #[primary_span]
         span: Span,
     },
-    #[label(expand::explain_doc_comment_outer)]
+    #[label(expand_explain_doc_comment_outer)]
     Outer {
         #[primary_span]
         span: Span,
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 3b0d5ddb97b..faaf3b3fea5 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -55,6 +55,7 @@ pub fn placeholder(
         }),
         AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
         AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
+        AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(expr_placeholder()),
         AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item {
             id,
             span,
@@ -296,6 +297,13 @@ impl MutVisitor for PlaceholderExpander {
         }
     }
 
+    fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
+        match expr.kind {
+            ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_method_receiver_expr(),
+            _ => noop_visit_expr(expr, self),
+        }
+    }
+
     fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
         match expr.kind {
             ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(),
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index e44f0608196..d82a7a54030 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -151,6 +151,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
             false,
             None,
             false,
+            false,
         );
         let handler = Handler::with_emitter(true, None, Box::new(emitter));
         handler.span_err(msp, "foo");
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index ca12659695f..db289a64046 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -53,6 +53,10 @@ declare_features! (
     (accepted, abi_sysv64, "1.24.0", Some(36167), None),
     /// Allows using ADX intrinsics from `core::arch::{x86, x86_64}`.
     (accepted, adx_target_feature, "1.61.0", Some(44839), None),
+    /// Allows explicit discriminants on non-unit enum variants.
+    (accepted, arbitrary_enum_discriminant, "CURRENT_RUSTC_VERSION", Some(60553), None),
+    /// Allows using `sym` operands in inline assembly.
+    (accepted, asm_sym, "CURRENT_RUSTC_VERSION", Some(93333), None),
     /// Allows the definition of associated constants in `trait` or `impl` blocks.
     (accepted, associated_consts, "1.20.0", Some(29646), None),
     /// Allows using associated `type`s in `trait`s.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 5ea433e6b3d..7900f150048 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -292,16 +292,12 @@ declare_features! (
     (incomplete, adt_const_params, "1.56.0", Some(95174), None),
     /// Allows defining an `#[alloc_error_handler]`.
     (active, alloc_error_handler, "1.29.0", Some(51540), None),
-    /// Allows explicit discriminants on non-unit enum variants.
-    (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
     /// Allows trait methods with arbitrary self types.
     (active, arbitrary_self_types, "1.23.0", Some(44874), None),
     /// Allows using `const` operands in inline assembly.
     (active, asm_const, "1.58.0", Some(93332), None),
     /// Enables experimental inline assembly support for additional architectures.
     (active, asm_experimental_arch, "1.58.0", Some(93335), None),
-    /// Allows using `sym` operands in inline assembly.
-    (active, asm_sym, "1.58.0", Some(93333), None),
     /// Allows the `may_unwind` option in inline assembly.
     (active, asm_unwind, "1.58.0", Some(93334), None),
     /// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
@@ -392,6 +388,9 @@ declare_features! (
     (active, exclusive_range_pattern, "1.11.0", Some(37854), None),
     /// Allows exhaustive pattern matching on types that contain uninhabited types.
     (active, exhaustive_patterns, "1.13.0", Some(51085), None),
+    /// Allows using `efiapi`, `sysv64` and `win64` as calling convention
+    /// for functions with varargs.
+    (active, extended_varargs_abi_support, "1.65.0", Some(100189), None),
     /// Allows defining `extern type`s.
     (active, extern_types, "1.23.0", Some(43467), None),
     /// Allows the use of `#[ffi_const]` on foreign functions.
@@ -416,6 +415,8 @@ declare_features! (
     (active, half_open_range_patterns_in_slices, "CURRENT_RUSTC_VERSION", Some(67264), None),
     /// Allows `if let` guard in match arms.
     (active, if_let_guard, "1.47.0", Some(51114), None),
+    /// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
+    (active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None),
     /// Allows using imported `main` function
     (active, imported_main, "1.53.0", Some(28937), None),
     /// Allows associated types in inherent impls.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 92d0fb1aec8..14c8e3c458c 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -296,20 +296,24 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     // Lints:
     ungated!(
-        warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+        warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        DuplicatesOk, @only_local: true,
     ),
     ungated!(
-        allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+        allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        DuplicatesOk, @only_local: true,
     ),
     gated!(
         expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk,
         lint_reasons, experimental!(expect)
     ),
     ungated!(
-        forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+        forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        DuplicatesOk, @only_local: true,
     ),
     ungated!(
-        deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+        deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        DuplicatesOk, @only_local: true,
     ),
     ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing),
     gated!(
@@ -340,7 +344,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
     ungated!(no_link, Normal, template!(Word), WarnFollowing),
-    ungated!(repr, Normal, template!(List: "C"), DuplicatesOk),
+    ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true),
     ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
     ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
     ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true),
@@ -382,7 +386,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, @only_local: true),
     ungated!(cold, Normal, template!(Word), WarnFollowing, @only_local: true),
     ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing),
-    ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk),
+    ungated!(
+        target_feature, Normal, template!(List: r#"enable = "name""#),
+        DuplicatesOk, @only_local: true,
+    ),
     ungated!(track_caller, Normal, template!(Word), WarnFollowing),
     gated!(
         no_sanitize, Normal,
@@ -488,18 +495,24 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // Internal attributes: Stability, deprecation, and unsafe:
     // ==========================================================================
 
-    ungated!(feature, CrateLevel, template!(List: "name1, name2, ..."), DuplicatesOk),
+    ungated!(
+        feature, CrateLevel,
+        template!(List: "name1, name2, ..."), DuplicatesOk, @only_local: true,
+    ),
     // DuplicatesOk since it has its own validation
     ungated!(
-        stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk,
+        stable, Normal,
+        template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, @only_local: true,
     ),
     ungated!(
         unstable, Normal,
         template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk,
     ),
     ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
-    ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
-    ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk),
+    ungated!(
+        rustc_const_stable, Normal,
+        template!(List: r#"feature = "name""#), DuplicatesOk, @only_local: true,
+    ),
     ungated!(
         rustc_default_body_unstable, Normal,
         template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk
@@ -517,6 +530,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
         "allow_internal_unsafe side-steps the unsafe_code lint",
     ),
+    ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk),
     rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing,
     "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
     through unstable paths"),
@@ -541,10 +555,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
     rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
     gated!(
-        alloc_error_handler, Normal, template!(Word), WarnFollowing,
-        experimental!(alloc_error_handler)
-    ),
-    gated!(
         default_lib_allocator, Normal, template!(Word), WarnFollowing, allocator_internals,
         experimental!(default_lib_allocator),
     ),
@@ -732,7 +742,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
          for reserving for `for<T> From<!> for T` impl"
     ),
     rustc_attr!(
-        rustc_test_marker, Normal, template!(Word), WarnFollowing,
+        rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing,
         "the `#[rustc_test_marker]` attribute is used internally to track tests",
     ),
     rustc_attr!(
@@ -823,6 +833,8 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool {
     BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
 }
 
+/// Whether this builtin attribute is only used in the local crate.
+/// If so, it is not encoded in the crate metadata.
 pub fn is_builtin_only_local(name: Symbol) -> bool {
     BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local)
 }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index bc149e48d89..ef00c1ffc30 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2207,14 +2207,14 @@ pub struct FnSig<'hir> {
 // so it can fetched later.
 #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct TraitItemId {
-    pub def_id: OwnerId,
+    pub owner_id: OwnerId,
 }
 
 impl TraitItemId {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id.def_id)
+        HirId::make_owner(self.owner_id.def_id)
     }
 }
 
@@ -2225,7 +2225,7 @@ impl TraitItemId {
 #[derive(Debug, HashStable_Generic)]
 pub struct TraitItem<'hir> {
     pub ident: Ident,
-    pub def_id: OwnerId,
+    pub owner_id: OwnerId,
     pub generics: &'hir Generics<'hir>,
     pub kind: TraitItemKind<'hir>,
     pub span: Span,
@@ -2236,11 +2236,11 @@ impl TraitItem<'_> {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id.def_id)
+        HirId::make_owner(self.owner_id.def_id)
     }
 
     pub fn trait_item_id(&self) -> TraitItemId {
-        TraitItemId { def_id: self.def_id }
+        TraitItemId { owner_id: self.owner_id }
     }
 }
 
@@ -2271,14 +2271,14 @@ pub enum TraitItemKind<'hir> {
 // so it can fetched later.
 #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct ImplItemId {
-    pub def_id: OwnerId,
+    pub owner_id: OwnerId,
 }
 
 impl ImplItemId {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id.def_id)
+        HirId::make_owner(self.owner_id.def_id)
     }
 }
 
@@ -2286,7 +2286,7 @@ impl ImplItemId {
 #[derive(Debug, HashStable_Generic)]
 pub struct ImplItem<'hir> {
     pub ident: Ident,
-    pub def_id: OwnerId,
+    pub owner_id: OwnerId,
     pub generics: &'hir Generics<'hir>,
     pub kind: ImplItemKind<'hir>,
     pub defaultness: Defaultness,
@@ -2298,11 +2298,11 @@ impl ImplItem<'_> {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id.def_id)
+        HirId::make_owner(self.owner_id.def_id)
     }
 
     pub fn impl_item_id(&self) -> ImplItemId {
-        ImplItemId { def_id: self.def_id }
+        ImplItemId { owner_id: self.owner_id }
     }
 }
 
@@ -2418,6 +2418,30 @@ impl<'hir> Ty<'hir> {
         }
         final_ty
     }
+
+    pub fn find_self_aliases(&self) -> Vec<Span> {
+        use crate::intravisit::Visitor;
+        struct MyVisitor(Vec<Span>);
+        impl<'v> Visitor<'v> for MyVisitor {
+            fn visit_ty(&mut self, t: &'v Ty<'v>) {
+                if matches!(
+                    &t.kind,
+                    TyKind::Path(QPath::Resolved(
+                        _,
+                        Path { res: crate::def::Res::SelfTyAlias { .. }, .. },
+                    ))
+                ) {
+                    self.0.push(t.span);
+                    return;
+                }
+                crate::intravisit::walk_ty(self, t);
+            }
+        }
+
+        let mut my_visitor = MyVisitor(vec![]);
+        my_visitor.visit_ty(self);
+        my_visitor.0
+    }
 }
 
 /// Not represented directly in the AST; referred to by name through a `ty_path`.
@@ -2890,14 +2914,14 @@ impl<'hir> VariantData<'hir> {
 // so it can fetched later.
 #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
 pub struct ItemId {
-    pub def_id: OwnerId,
+    pub owner_id: OwnerId,
 }
 
 impl ItemId {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id.def_id)
+        HirId::make_owner(self.owner_id.def_id)
     }
 }
 
@@ -2907,7 +2931,7 @@ impl ItemId {
 #[derive(Debug, HashStable_Generic)]
 pub struct Item<'hir> {
     pub ident: Ident,
-    pub def_id: OwnerId,
+    pub owner_id: OwnerId,
     pub kind: ItemKind<'hir>,
     pub span: Span,
     pub vis_span: Span,
@@ -2917,11 +2941,11 @@ impl Item<'_> {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id.def_id)
+        HirId::make_owner(self.owner_id.def_id)
     }
 
     pub fn item_id(&self) -> ItemId {
-        ItemId { def_id: self.def_id }
+        ItemId { owner_id: self.owner_id }
     }
 }
 
@@ -3134,14 +3158,14 @@ pub enum AssocItemKind {
 // so it can fetched later.
 #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct ForeignItemId {
-    pub def_id: OwnerId,
+    pub owner_id: OwnerId,
 }
 
 impl ForeignItemId {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id.def_id)
+        HirId::make_owner(self.owner_id.def_id)
     }
 }
 
@@ -3162,7 +3186,7 @@ pub struct ForeignItemRef {
 pub struct ForeignItem<'hir> {
     pub ident: Ident,
     pub kind: ForeignItemKind<'hir>,
-    pub def_id: OwnerId,
+    pub owner_id: OwnerId,
     pub span: Span,
     pub vis_span: Span,
 }
@@ -3171,11 +3195,11 @@ impl ForeignItem<'_> {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id.def_id)
+        HirId::make_owner(self.owner_id.def_id)
     }
 
     pub fn foreign_item_id(&self) -> ForeignItemId {
-        ForeignItemId { def_id: self.def_id }
+        ForeignItemId { owner_id: self.owner_id }
     }
 }
 
@@ -3267,10 +3291,10 @@ impl<'hir> OwnerNode<'hir> {
 
     pub fn def_id(self) -> OwnerId {
         match self {
-            OwnerNode::Item(Item { def_id, .. })
-            | OwnerNode::TraitItem(TraitItem { def_id, .. })
-            | OwnerNode::ImplItem(ImplItem { def_id, .. })
-            | OwnerNode::ForeignItem(ForeignItem { def_id, .. }) => *def_id,
+            OwnerNode::Item(Item { owner_id, .. })
+            | OwnerNode::TraitItem(TraitItem { owner_id, .. })
+            | OwnerNode::ImplItem(ImplItem { owner_id, .. })
+            | OwnerNode::ForeignItem(ForeignItem { owner_id, .. }) => *owner_id,
             OwnerNode::Crate(..) => crate::CRATE_HIR_ID.owner,
         }
     }
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index f3bde099b13..3ef58d7d705 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -358,6 +358,9 @@ pub trait Visitor<'v>: Sized {
     fn visit_where_predicate(&mut self, predicate: &'v WherePredicate<'v>) {
         walk_where_predicate(self, predicate)
     }
+    fn visit_fn_ret_ty(&mut self, ret_ty: &'v FnRetTy<'v>) {
+        walk_fn_ret_ty(self, ret_ty)
+    }
     fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) {
         walk_fn_decl(self, fd)
     }
@@ -410,12 +413,7 @@ pub trait Visitor<'v>: Sized {
         walk_inf(self, inf);
     }
     fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) {
-        match generic_arg {
-            GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
-            GenericArg::Type(ty) => self.visit_ty(ty),
-            GenericArg::Const(ct) => self.visit_anon_const(&ct.value),
-            GenericArg::Infer(inf) => self.visit_infer(inf),
-        }
+        walk_generic_arg(self, generic_arg);
     }
     fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
         walk_lifetime(self, lifetime)
@@ -448,63 +446,6 @@ pub trait Visitor<'v>: Sized {
     }
 }
 
-pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) {
-    visitor.visit_id(mod_hir_id);
-    for &item_id in module.item_ids {
-        visitor.visit_nested_item(item_id);
-    }
-}
-
-pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) {
-    walk_list!(visitor, visit_param, body.params);
-    visitor.visit_expr(&body.value);
-}
-
-pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) {
-    // Intentionally visiting the expr first - the initialization expr
-    // dominates the local's definition.
-    walk_list!(visitor, visit_expr, &local.init);
-    visitor.visit_id(local.hir_id);
-    visitor.visit_pat(&local.pat);
-    if let Some(els) = local.els {
-        visitor.visit_block(els);
-    }
-    walk_list!(visitor, visit_ty, &local.ty);
-}
-
-pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) {
-    visitor.visit_name(ident.name);
-}
-
-pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) {
-    visitor.visit_ident(label.ident);
-}
-
-pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
-    visitor.visit_id(lifetime.hir_id);
-    match lifetime.name {
-        LifetimeName::Param(_, ParamName::Plain(ident)) => {
-            visitor.visit_ident(ident);
-        }
-        LifetimeName::Param(_, ParamName::Fresh)
-        | LifetimeName::Param(_, ParamName::Error)
-        | LifetimeName::Static
-        | LifetimeName::Error
-        | LifetimeName::ImplicitObjectLifetimeDefault
-        | LifetimeName::Infer => {}
-    }
-}
-
-pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v PolyTraitRef<'v>) {
-    walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params);
-    visitor.visit_trait_ref(&trait_ref.trait_ref);
-}
-
-pub fn walk_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v TraitRef<'v>) {
-    visitor.visit_id(trait_ref.hir_ref_id);
-    visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id)
-}
-
 pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) {
     visitor.visit_id(param.hir_id);
     visitor.visit_pat(&param.pat);
@@ -601,142 +542,80 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
     }
 }
 
-pub fn walk_inline_asm<'v, V: Visitor<'v>>(visitor: &mut V, asm: &'v InlineAsm<'v>, id: HirId) {
-    for (op, op_sp) in asm.operands {
-        match op {
-            InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
-                visitor.visit_expr(expr)
-            }
-            InlineAsmOperand::Out { expr, .. } => {
-                if let Some(expr) = expr {
-                    visitor.visit_expr(expr);
-                }
-            }
-            InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
-                visitor.visit_expr(in_expr);
-                if let Some(out_expr) = out_expr {
-                    visitor.visit_expr(out_expr);
-                }
-            }
-            InlineAsmOperand::Const { anon_const, .. }
-            | InlineAsmOperand::SymFn { anon_const, .. } => visitor.visit_anon_const(anon_const),
-            InlineAsmOperand::SymStatic { path, .. } => visitor.visit_qpath(path, id, *op_sp),
-        }
-    }
-}
-
-pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>, hir_id: HirId) {
-    visitor.visit_id(hir_id);
-    visitor.visit_path(path, hir_id);
+pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) {
+    walk_list!(visitor, visit_param, body.params);
+    visitor.visit_expr(&body.value);
 }
 
-pub fn walk_enum_def<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    enum_definition: &'v EnumDef<'v>,
-    item_id: HirId,
-) {
-    visitor.visit_id(item_id);
-    walk_list!(visitor, visit_variant, enum_definition.variants);
+pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) {
+    visitor.visit_name(ident.name);
 }
 
-pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) {
-    visitor.visit_ident(variant.ident);
-    visitor.visit_id(variant.id);
-    visitor.visit_variant_data(&variant.data);
-    walk_list!(visitor, visit_anon_const, &variant.disr_expr);
+pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) {
+    visitor.visit_id(mod_hir_id);
+    for &item_id in module.item_ids {
+        visitor.visit_nested_item(item_id);
+    }
 }
 
-pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
-    visitor.visit_id(typ.hir_id);
+pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem<'v>) {
+    visitor.visit_id(foreign_item.hir_id());
+    visitor.visit_ident(foreign_item.ident);
 
-    match typ.kind {
-        TyKind::Slice(ref ty) => visitor.visit_ty(ty),
-        TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
-        TyKind::Rptr(ref lifetime, ref mutable_type) => {
-            visitor.visit_lifetime(lifetime);
-            visitor.visit_ty(&mutable_type.ty)
-        }
-        TyKind::Never => {}
-        TyKind::Tup(tuple_element_types) => {
-            walk_list!(visitor, visit_ty, tuple_element_types);
-        }
-        TyKind::BareFn(ref function_declaration) => {
-            walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
-            visitor.visit_fn_decl(&function_declaration.decl);
-        }
-        TyKind::Path(ref qpath) => {
-            visitor.visit_qpath(qpath, typ.hir_id, typ.span);
-        }
-        TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => {
-            visitor.visit_nested_item(item_id);
-            walk_list!(visitor, visit_generic_arg, lifetimes);
-        }
-        TyKind::Array(ref ty, ref length) => {
-            visitor.visit_ty(ty);
-            visitor.visit_array_length(length)
-        }
-        TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
-            for bound in bounds {
-                visitor.visit_poly_trait_ref(bound);
+    match foreign_item.kind {
+        ForeignItemKind::Fn(ref function_declaration, param_names, ref generics) => {
+            visitor.visit_generics(generics);
+            visitor.visit_fn_decl(function_declaration);
+            for &param_name in param_names {
+                visitor.visit_ident(param_name);
             }
-            visitor.visit_lifetime(lifetime);
         }
-        TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
-        TyKind::Infer | TyKind::Err => {}
+        ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
+        ForeignItemKind::Type => (),
     }
 }
 
-pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) {
-    visitor.visit_id(inf.hir_id);
-}
-
-pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath<'v>, id: HirId) {
-    match *qpath {
-        QPath::Resolved(ref maybe_qself, ref path) => {
-            walk_list!(visitor, visit_ty, maybe_qself);
-            visitor.visit_path(path, id)
-        }
-        QPath::TypeRelative(ref qself, ref segment) => {
-            visitor.visit_ty(qself);
-            visitor.visit_path_segment(segment);
-        }
-        QPath::LangItem(..) => {}
+pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) {
+    // Intentionally visiting the expr first - the initialization expr
+    // dominates the local's definition.
+    walk_list!(visitor, visit_expr, &local.init);
+    visitor.visit_id(local.hir_id);
+    visitor.visit_pat(&local.pat);
+    if let Some(els) = local.els {
+        visitor.visit_block(els);
     }
+    walk_list!(visitor, visit_ty, &local.ty);
 }
 
-pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>) {
-    for segment in path.segments {
-        visitor.visit_path_segment(segment);
-    }
+pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) {
+    visitor.visit_id(block.hir_id);
+    walk_list!(visitor, visit_stmt, block.stmts);
+    walk_list!(visitor, visit_expr, &block.expr);
 }
 
-pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, segment: &'v PathSegment<'v>) {
-    visitor.visit_ident(segment.ident);
-    visitor.visit_id(segment.hir_id);
-    if let Some(ref args) = segment.args {
-        visitor.visit_generic_args(args);
+pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
+    visitor.visit_id(statement.hir_id);
+    match statement.kind {
+        StmtKind::Local(ref local) => visitor.visit_local(local),
+        StmtKind::Item(item) => visitor.visit_nested_item(item),
+        StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
+            visitor.visit_expr(expression)
+        }
     }
 }
 
-pub fn walk_generic_args<'v, V: Visitor<'v>>(visitor: &mut V, generic_args: &'v GenericArgs<'v>) {
-    walk_list!(visitor, visit_generic_arg, generic_args.args);
-    walk_list!(visitor, visit_assoc_type_binding, generic_args.bindings);
-}
-
-pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    type_binding: &'v TypeBinding<'v>,
-) {
-    visitor.visit_id(type_binding.hir_id);
-    visitor.visit_ident(type_binding.ident);
-    visitor.visit_generic_args(type_binding.gen_args);
-    match type_binding.kind {
-        TypeBindingKind::Equality { ref term } => match term {
-            Term::Ty(ref ty) => visitor.visit_ty(ty),
-            Term::Const(ref c) => visitor.visit_anon_const(c),
-        },
-        TypeBindingKind::Constraint { bounds } => walk_list!(visitor, visit_param_bound, bounds),
+pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) {
+    visitor.visit_id(arm.hir_id);
+    visitor.visit_pat(&arm.pat);
+    if let Some(ref g) = arm.guard {
+        match g {
+            Guard::If(ref e) => visitor.visit_expr(e),
+            Guard::IfLet(ref l) => {
+                visitor.visit_let_expr(l);
+            }
+        }
     }
+    visitor.visit_expr(&arm.body);
 }
 
 pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
@@ -784,33 +663,181 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'
     visitor.visit_pat(&field.pat)
 }
 
-pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem<'v>) {
-    visitor.visit_id(foreign_item.hir_id());
-    visitor.visit_ident(foreign_item.ident);
+pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
+    match len {
+        &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id),
+        ArrayLen::Body(c) => visitor.visit_anon_const(c),
+    }
+}
 
-    match foreign_item.kind {
-        ForeignItemKind::Fn(ref function_declaration, param_names, ref generics) => {
-            visitor.visit_generics(generics);
-            visitor.visit_fn_decl(function_declaration);
-            for &param_name in param_names {
-                visitor.visit_ident(param_name);
-            }
+pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
+    visitor.visit_id(constant.hir_id);
+    visitor.visit_nested_body(constant.body);
+}
+
+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);
         }
-        ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
-        ForeignItemKind::Type => (),
+        ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
+        ExprKind::Repeat(ref element, ref count) => {
+            visitor.visit_expr(element);
+            visitor.visit_array_length(count)
+        }
+        ExprKind::Struct(ref qpath, fields, ref optional_base) => {
+            visitor.visit_qpath(qpath, expression.hir_id, expression.span);
+            walk_list!(visitor, visit_expr_field, fields);
+            walk_list!(visitor, visit_expr, optional_base);
+        }
+        ExprKind::Tup(subexpressions) => {
+            walk_list!(visitor, visit_expr, subexpressions);
+        }
+        ExprKind::Call(ref callee_expression, arguments) => {
+            visitor.visit_expr(callee_expression);
+            walk_list!(visitor, visit_expr, arguments);
+        }
+        ExprKind::MethodCall(ref segment, receiver, arguments, _) => {
+            visitor.visit_path_segment(segment);
+            visitor.visit_expr(receiver);
+            walk_list!(visitor, visit_expr, arguments);
+        }
+        ExprKind::Binary(_, ref left_expression, ref right_expression) => {
+            visitor.visit_expr(left_expression);
+            visitor.visit_expr(right_expression)
+        }
+        ExprKind::AddrOf(_, _, ref subexpression) | ExprKind::Unary(_, ref subexpression) => {
+            visitor.visit_expr(subexpression)
+        }
+        ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
+            visitor.visit_expr(subexpression);
+            visitor.visit_ty(typ)
+        }
+        ExprKind::DropTemps(ref subexpression) => {
+            visitor.visit_expr(subexpression);
+        }
+        ExprKind::Let(ref let_expr) => visitor.visit_let_expr(let_expr),
+        ExprKind::If(ref cond, ref then, ref else_opt) => {
+            visitor.visit_expr(cond);
+            visitor.visit_expr(then);
+            walk_list!(visitor, visit_expr, else_opt);
+        }
+        ExprKind::Loop(ref block, ref opt_label, _, _) => {
+            walk_list!(visitor, visit_label, opt_label);
+            visitor.visit_block(block);
+        }
+        ExprKind::Match(ref subexpression, arms, _) => {
+            visitor.visit_expr(subexpression);
+            walk_list!(visitor, visit_arm, arms);
+        }
+        ExprKind::Closure(&Closure {
+            binder: _,
+            bound_generic_params,
+            fn_decl,
+            body,
+            capture_clause: _,
+            fn_decl_span: _,
+            movability: _,
+        }) => {
+            walk_list!(visitor, visit_generic_param, bound_generic_params);
+            visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
+        }
+        ExprKind::Block(ref block, ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
+            visitor.visit_block(block);
+        }
+        ExprKind::Assign(ref lhs, ref rhs, _) => {
+            visitor.visit_expr(rhs);
+            visitor.visit_expr(lhs)
+        }
+        ExprKind::AssignOp(_, ref left_expression, ref right_expression) => {
+            visitor.visit_expr(right_expression);
+            visitor.visit_expr(left_expression);
+        }
+        ExprKind::Field(ref subexpression, ident) => {
+            visitor.visit_expr(subexpression);
+            visitor.visit_ident(ident);
+        }
+        ExprKind::Index(ref main_expression, ref index_expression) => {
+            visitor.visit_expr(main_expression);
+            visitor.visit_expr(index_expression)
+        }
+        ExprKind::Path(ref qpath) => {
+            visitor.visit_qpath(qpath, expression.hir_id, expression.span);
+        }
+        ExprKind::Break(ref destination, ref opt_expr) => {
+            walk_list!(visitor, visit_label, &destination.label);
+            walk_list!(visitor, visit_expr, opt_expr);
+        }
+        ExprKind::Continue(ref destination) => {
+            walk_list!(visitor, visit_label, &destination.label);
+        }
+        ExprKind::Ret(ref optional_expression) => {
+            walk_list!(visitor, visit_expr, optional_expression);
+        }
+        ExprKind::InlineAsm(ref asm) => {
+            visitor.visit_inline_asm(asm, expression.hir_id);
+        }
+        ExprKind::Yield(ref subexpression, _) => {
+            visitor.visit_expr(subexpression);
+        }
+        ExprKind::Lit(_) | ExprKind::Err => {}
     }
 }
 
-pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericBound<'v>) {
-    match *bound {
-        GenericBound::Trait(ref typ, _modifier) => {
-            visitor.visit_poly_trait_ref(typ);
+pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) {
+    // match the visit order in walk_local
+    visitor.visit_expr(let_expr.init);
+    visitor.visit_id(let_expr.hir_id);
+    visitor.visit_pat(let_expr.pat);
+    walk_list!(visitor, visit_ty, let_expr.ty);
+}
+
+pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) {
+    visitor.visit_id(field.hir_id);
+    visitor.visit_ident(field.ident);
+    visitor.visit_expr(&field.expr)
+}
+
+pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
+    visitor.visit_id(typ.hir_id);
+
+    match typ.kind {
+        TyKind::Slice(ref ty) => visitor.visit_ty(ty),
+        TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
+        TyKind::Rptr(ref lifetime, ref mutable_type) => {
+            visitor.visit_lifetime(lifetime);
+            visitor.visit_ty(&mutable_type.ty)
         }
-        GenericBound::LangItemTrait(_, _span, hir_id, args) => {
-            visitor.visit_id(hir_id);
-            visitor.visit_generic_args(args);
+        TyKind::Never => {}
+        TyKind::Tup(tuple_element_types) => {
+            walk_list!(visitor, visit_ty, tuple_element_types);
         }
-        GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
+        TyKind::BareFn(ref function_declaration) => {
+            walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
+            visitor.visit_fn_decl(&function_declaration.decl);
+        }
+        TyKind::Path(ref qpath) => {
+            visitor.visit_qpath(qpath, typ.hir_id, typ.span);
+        }
+        TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => {
+            visitor.visit_nested_item(item_id);
+            walk_list!(visitor, visit_generic_arg, lifetimes);
+        }
+        TyKind::Array(ref ty, ref length) => {
+            visitor.visit_ty(ty);
+            visitor.visit_array_length(length)
+        }
+        TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
+            for bound in bounds {
+                visitor.visit_poly_trait_ref(bound);
+            }
+            visitor.visit_lifetime(lifetime);
+        }
+        TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
+        TyKind::Infer | TyKind::Err => {}
     }
 }
 
@@ -875,25 +902,16 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
     }
 }
 
-pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) {
-    if let FnRetTy::Return(ref output_ty) = *ret_ty {
-        visitor.visit_ty(output_ty)
-    }
-}
-
 pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl<'v>) {
     for ty in function_declaration.inputs {
         visitor.visit_ty(ty)
     }
-    walk_fn_ret_ty(visitor, &function_declaration.output)
+    visitor.visit_fn_ret_ty(&function_declaration.output)
 }
 
-pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) {
-    match function_kind {
-        FnKind::ItemFn(_, generics, ..) => {
-            visitor.visit_generics(generics);
-        }
-        FnKind::Closure | FnKind::Method(..) => {}
+pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) {
+    if let FnRetTy::Return(ref output_ty) = *ret_ty {
+        visitor.visit_ty(output_ty)
     }
 }
 
@@ -910,9 +928,23 @@ pub fn walk_fn<'v, V: Visitor<'v>>(
     visitor.visit_nested_body(body_id)
 }
 
+pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) {
+    match function_kind {
+        FnKind::ItemFn(_, generics, ..) => {
+            visitor.visit_generics(generics);
+        }
+        FnKind::Closure | FnKind::Method(..) => {}
+    }
+}
+
+pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>, hir_id: HirId) {
+    visitor.visit_id(hir_id);
+    visitor.visit_path(path, hir_id);
+}
+
 pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let TraitItem { ident, generics, ref defaultness, ref kind, span, def_id: _ } = *trait_item;
+    let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item;
     let hir_id = trait_item.hir_id();
     visitor.visit_ident(ident);
     visitor.visit_generics(&generics);
@@ -952,7 +984,7 @@ pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref:
 pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
     // N.B., deliberately force a compilation error if/when new fields are added.
     let ImplItem {
-        def_id: _,
+        owner_id: _,
         ident,
         ref generics,
         ref kind,
@@ -1004,6 +1036,29 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'
     visitor.visit_associated_item_kind(kind);
 }
 
+pub fn walk_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v TraitRef<'v>) {
+    visitor.visit_id(trait_ref.hir_ref_id);
+    visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id)
+}
+
+pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericBound<'v>) {
+    match *bound {
+        GenericBound::Trait(ref typ, _modifier) => {
+            visitor.visit_poly_trait_ref(typ);
+        }
+        GenericBound::LangItemTrait(_, _span, hir_id, args) => {
+            visitor.visit_id(hir_id);
+            visitor.visit_generic_args(args);
+        }
+        GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
+    }
+}
+
+pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v PolyTraitRef<'v>) {
+    walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params);
+    visitor.visit_trait_ref(&trait_ref.trait_ref);
+}
+
 pub fn walk_struct_def<'v, V: Visitor<'v>>(
     visitor: &mut V,
     struct_definition: &'v VariantData<'v>,
@@ -1018,173 +1073,101 @@ pub fn walk_field_def<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v FieldDef<'
     visitor.visit_ty(&field.ty);
 }
 
-pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) {
-    visitor.visit_id(block.hir_id);
-    walk_list!(visitor, visit_stmt, block.stmts);
-    walk_list!(visitor, visit_expr, &block.expr);
+pub fn walk_enum_def<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    enum_definition: &'v EnumDef<'v>,
+    item_id: HirId,
+) {
+    visitor.visit_id(item_id);
+    walk_list!(visitor, visit_variant, enum_definition.variants);
 }
 
-pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
-    visitor.visit_id(statement.hir_id);
-    match statement.kind {
-        StmtKind::Local(ref local) => visitor.visit_local(local),
-        StmtKind::Item(item) => visitor.visit_nested_item(item),
-        StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
-            visitor.visit_expr(expression)
-        }
-    }
+pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) {
+    visitor.visit_ident(variant.ident);
+    visitor.visit_id(variant.id);
+    visitor.visit_variant_data(&variant.data);
+    walk_list!(visitor, visit_anon_const, &variant.disr_expr);
 }
 
-pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
-    match len {
-        &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id),
-        ArrayLen::Body(c) => visitor.visit_anon_const(c),
-    }
+pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) {
+    visitor.visit_ident(label.ident);
 }
 
-pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
-    visitor.visit_id(constant.hir_id);
-    visitor.visit_nested_body(constant.body);
+pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) {
+    visitor.visit_id(inf.hir_id);
 }
 
-pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) {
-    // match the visit order in walk_local
-    visitor.visit_expr(let_expr.init);
-    visitor.visit_id(let_expr.hir_id);
-    visitor.visit_pat(let_expr.pat);
-    walk_list!(visitor, visit_ty, let_expr.ty);
+pub fn walk_generic_arg<'v, V: Visitor<'v>>(visitor: &mut V, generic_arg: &'v GenericArg<'v>) {
+    match generic_arg {
+        GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
+        GenericArg::Type(ty) => visitor.visit_ty(ty),
+        GenericArg::Const(ct) => visitor.visit_anon_const(&ct.value),
+        GenericArg::Infer(inf) => visitor.visit_infer(inf),
+    }
 }
 
-pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) {
-    visitor.visit_id(field.hir_id);
-    visitor.visit_ident(field.ident);
-    visitor.visit_expr(&field.expr)
+pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
+    visitor.visit_id(lifetime.hir_id);
+    match lifetime.name {
+        LifetimeName::Param(_, ParamName::Plain(ident)) => {
+            visitor.visit_ident(ident);
+        }
+        LifetimeName::Param(_, ParamName::Fresh)
+        | LifetimeName::Param(_, ParamName::Error)
+        | LifetimeName::Static
+        | LifetimeName::Error
+        | LifetimeName::ImplicitObjectLifetimeDefault
+        | LifetimeName::Infer => {}
+    }
 }
 
-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);
-        }
-        ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
-        ExprKind::Repeat(ref element, ref count) => {
-            visitor.visit_expr(element);
-            visitor.visit_array_length(count)
-        }
-        ExprKind::Struct(ref qpath, fields, ref optional_base) => {
-            visitor.visit_qpath(qpath, expression.hir_id, expression.span);
-            walk_list!(visitor, visit_expr_field, fields);
-            walk_list!(visitor, visit_expr, optional_base);
-        }
-        ExprKind::Tup(subexpressions) => {
-            walk_list!(visitor, visit_expr, subexpressions);
-        }
-        ExprKind::Call(ref callee_expression, arguments) => {
-            visitor.visit_expr(callee_expression);
-            walk_list!(visitor, visit_expr, arguments);
+pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath<'v>, id: HirId) {
+    match *qpath {
+        QPath::Resolved(ref maybe_qself, ref path) => {
+            walk_list!(visitor, visit_ty, maybe_qself);
+            visitor.visit_path(path, id)
         }
-        ExprKind::MethodCall(ref segment, receiver, arguments, _) => {
+        QPath::TypeRelative(ref qself, ref segment) => {
+            visitor.visit_ty(qself);
             visitor.visit_path_segment(segment);
-            visitor.visit_expr(receiver);
-            walk_list!(visitor, visit_expr, arguments);
-        }
-        ExprKind::Binary(_, ref left_expression, ref right_expression) => {
-            visitor.visit_expr(left_expression);
-            visitor.visit_expr(right_expression)
-        }
-        ExprKind::AddrOf(_, _, ref subexpression) | ExprKind::Unary(_, ref subexpression) => {
-            visitor.visit_expr(subexpression)
-        }
-        ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
-            visitor.visit_expr(subexpression);
-            visitor.visit_ty(typ)
-        }
-        ExprKind::DropTemps(ref subexpression) => {
-            visitor.visit_expr(subexpression);
-        }
-        ExprKind::Let(ref let_expr) => visitor.visit_let_expr(let_expr),
-        ExprKind::If(ref cond, ref then, ref else_opt) => {
-            visitor.visit_expr(cond);
-            visitor.visit_expr(then);
-            walk_list!(visitor, visit_expr, else_opt);
-        }
-        ExprKind::Loop(ref block, ref opt_label, _, _) => {
-            walk_list!(visitor, visit_label, opt_label);
-            visitor.visit_block(block);
-        }
-        ExprKind::Match(ref subexpression, arms, _) => {
-            visitor.visit_expr(subexpression);
-            walk_list!(visitor, visit_arm, arms);
-        }
-        ExprKind::Closure(&Closure {
-            binder: _,
-            bound_generic_params,
-            fn_decl,
-            body,
-            capture_clause: _,
-            fn_decl_span: _,
-            movability: _,
-        }) => {
-            walk_list!(visitor, visit_generic_param, bound_generic_params);
-            visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
-        }
-        ExprKind::Block(ref block, ref opt_label) => {
-            walk_list!(visitor, visit_label, opt_label);
-            visitor.visit_block(block);
-        }
-        ExprKind::Assign(ref lhs, ref rhs, _) => {
-            visitor.visit_expr(rhs);
-            visitor.visit_expr(lhs)
-        }
-        ExprKind::AssignOp(_, ref left_expression, ref right_expression) => {
-            visitor.visit_expr(right_expression);
-            visitor.visit_expr(left_expression);
-        }
-        ExprKind::Field(ref subexpression, ident) => {
-            visitor.visit_expr(subexpression);
-            visitor.visit_ident(ident);
-        }
-        ExprKind::Index(ref main_expression, ref index_expression) => {
-            visitor.visit_expr(main_expression);
-            visitor.visit_expr(index_expression)
         }
-        ExprKind::Path(ref qpath) => {
-            visitor.visit_qpath(qpath, expression.hir_id, expression.span);
-        }
-        ExprKind::Break(ref destination, ref opt_expr) => {
-            walk_list!(visitor, visit_label, &destination.label);
-            walk_list!(visitor, visit_expr, opt_expr);
-        }
-        ExprKind::Continue(ref destination) => {
-            walk_list!(visitor, visit_label, &destination.label);
-        }
-        ExprKind::Ret(ref optional_expression) => {
-            walk_list!(visitor, visit_expr, optional_expression);
-        }
-        ExprKind::InlineAsm(ref asm) => {
-            visitor.visit_inline_asm(asm, expression.hir_id);
-        }
-        ExprKind::Yield(ref subexpression, _) => {
-            visitor.visit_expr(subexpression);
-        }
-        ExprKind::Lit(_) | ExprKind::Err => {}
+        QPath::LangItem(..) => {}
     }
 }
 
-pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) {
-    visitor.visit_id(arm.hir_id);
-    visitor.visit_pat(&arm.pat);
-    if let Some(ref g) = arm.guard {
-        match g {
-            Guard::If(ref e) => visitor.visit_expr(e),
-            Guard::IfLet(ref l) => {
-                visitor.visit_let_expr(l);
-            }
-        }
+pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>) {
+    for segment in path.segments {
+        visitor.visit_path_segment(segment);
+    }
+}
+
+pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, segment: &'v PathSegment<'v>) {
+    visitor.visit_ident(segment.ident);
+    visitor.visit_id(segment.hir_id);
+    if let Some(ref args) = segment.args {
+        visitor.visit_generic_args(args);
+    }
+}
+
+pub fn walk_generic_args<'v, V: Visitor<'v>>(visitor: &mut V, generic_args: &'v GenericArgs<'v>) {
+    walk_list!(visitor, visit_generic_arg, generic_args.args);
+    walk_list!(visitor, visit_assoc_type_binding, generic_args.bindings);
+}
+
+pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    type_binding: &'v TypeBinding<'v>,
+) {
+    visitor.visit_id(type_binding.hir_id);
+    visitor.visit_ident(type_binding.ident);
+    visitor.visit_generic_args(type_binding.gen_args);
+    match type_binding.kind {
+        TypeBindingKind::Equality { ref term } => match term {
+            Term::Ty(ref ty) => visitor.visit_ty(ty),
+            Term::Const(ref c) => visitor.visit_anon_const(c),
+        },
+        TypeBindingKind::Constraint { bounds } => walk_list!(visitor, visit_param_bound, bounds),
     }
-    visitor.visit_expr(&arm.body);
 }
 
 pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssocItemKind) {
@@ -1198,3 +1181,27 @@ pub fn walk_defaultness<'v, V: Visitor<'v>>(_: &mut V, _: &'v Defaultness) {
     // the right thing to do, should content be added in the future,
     // would be to walk it.
 }
+
+pub fn walk_inline_asm<'v, V: Visitor<'v>>(visitor: &mut V, asm: &'v InlineAsm<'v>, id: HirId) {
+    for (op, op_sp) in asm.operands {
+        match op {
+            InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
+                visitor.visit_expr(expr)
+            }
+            InlineAsmOperand::Out { expr, .. } => {
+                if let Some(expr) = expr {
+                    visitor.visit_expr(expr);
+                }
+            }
+            InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
+                visitor.visit_expr(in_expr);
+                if let Some(out_expr) = out_expr {
+                    visitor.visit_expr(out_expr);
+                }
+            }
+            InlineAsmOperand::Const { anon_const, .. }
+            | InlineAsmOperand::SymFn { anon_const, .. } => visitor.visit_anon_const(anon_const),
+            InlineAsmOperand::SymStatic { path, .. } => visitor.visit_qpath(path, id, *op_sp),
+        }
+    }
+}
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index ca615a4912a..a55224d1097 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -12,35 +12,56 @@ use crate::errors::LangItemError;
 use crate::{MethodKind, Target};
 
 use rustc_ast as ast;
-use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable_Generic;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 
-use std::sync::LazyLock;
-
-pub enum LangItemGroup {
-    Op,
-    Fn,
+/// All of the language items, defined or not.
+/// Defined lang items can come from the current crate or its dependencies.
+#[derive(HashStable_Generic, Debug)]
+pub struct LanguageItems {
+    /// Mappings from lang items to their possibly found [`DefId`]s.
+    /// The index corresponds to the order in [`LangItem`].
+    items: [Option<DefId>; std::mem::variant_count::<LangItem>()],
+    /// Lang items that were not found during collection.
+    pub missing: Vec<LangItem>,
 }
 
-const NUM_GROUPS: usize = 2;
+impl LanguageItems {
+    /// Construct an empty collection of lang items and no missing ones.
+    pub fn new() -> Self {
+        Self { items: [None; std::mem::variant_count::<LangItem>()], missing: Vec::new() }
+    }
+
+    pub fn get(&self, item: LangItem) -> Option<DefId> {
+        self.items[item as usize]
+    }
 
-macro_rules! expand_group {
-    () => {
-        None
-    };
-    ($group:expr) => {
-        Some($group)
-    };
+    pub fn set(&mut self, item: LangItem, def_id: DefId) {
+        self.items[item as usize] = Some(def_id);
+    }
+
+    /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`.
+    /// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`,
+    /// returns an error encapsulating the `LangItem`.
+    pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> {
+        self.get(it).ok_or_else(|| LangItemError(it))
+    }
+
+    pub fn iter<'a>(&'a self) -> impl Iterator<Item = (LangItem, DefId)> + 'a {
+        self.items
+            .iter()
+            .enumerate()
+            .filter_map(|(i, id)| id.map(|id| (LangItem::from_u32(i as u32).unwrap(), id)))
+    }
 }
 
 // The actual lang items defined come at the end of this file in one handy table.
 // So you probably just want to nip down to the end.
 macro_rules! language_item_table {
     (
-        $( $(#[$attr:meta])* $variant:ident $($group:expr)?, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )*
+        $( $(#[$attr:meta])* $variant:ident, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )*
     ) => {
 
         enum_from_u32! {
@@ -66,12 +87,17 @@ macro_rules! language_item_table {
                 }
             }
 
-            /// The [group](LangItemGroup) that this lang item belongs to,
-            /// or `None` if it doesn't belong to a group.
-            pub fn group(self) -> Option<LangItemGroup> {
-                use LangItemGroup::*;
+            /// Opposite of [`LangItem::name`]
+            pub fn from_name(name: Symbol) -> Option<Self> {
+                match name {
+                    $( $module::$name => Some(LangItem::$variant), )*
+                    _ => None,
+                }
+            }
+
+            pub fn target(self) -> Target {
                 match self {
-                    $( LangItem::$variant => expand_group!($($group)*), )*
+                    $( LangItem::$variant => $target, )*
                 }
             }
 
@@ -82,50 +108,7 @@ macro_rules! language_item_table {
             }
         }
 
-        /// All of the language items, defined or not.
-        /// Defined lang items can come from the current crate or its dependencies.
-        #[derive(HashStable_Generic, Debug)]
-        pub struct LanguageItems {
-            /// Mappings from lang items to their possibly found [`DefId`]s.
-            /// The index corresponds to the order in [`LangItem`].
-            pub items: Vec<Option<DefId>>,
-            /// Lang items that were not found during collection.
-            pub missing: Vec<LangItem>,
-            /// Mapping from [`LangItemGroup`] discriminants to all
-            /// [`DefId`]s of lang items in that group.
-            pub groups: [Vec<DefId>; NUM_GROUPS],
-        }
-
         impl LanguageItems {
-            /// Construct an empty collection of lang items and no missing ones.
-            pub fn new() -> Self {
-                fn init_none(_: LangItem) -> Option<DefId> { None }
-                const EMPTY: Vec<DefId> = Vec::new();
-
-                Self {
-                    items: vec![$(init_none(LangItem::$variant)),*],
-                    missing: Vec::new(),
-                    groups: [EMPTY; NUM_GROUPS],
-                }
-            }
-
-            /// Returns the mappings to the possibly found `DefId`s for each lang item.
-            pub fn items(&self) -> &[Option<DefId>] {
-                &*self.items
-            }
-
-            /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`.
-            /// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`,
-            /// returns an error encapsulating the `LangItem`.
-            pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> {
-                self.items[it as usize].ok_or_else(|| LangItemError(it))
-            }
-
-            /// Returns the [`DefId`]s of all lang items in a group.
-            pub fn group(&self, group: LangItemGroup) -> &[DefId] {
-                self.groups[group as usize].as_ref()
-            }
-
             $(
                 #[doc = concat!("Returns the [`DefId`] of the `", stringify!($name), "` lang item if it is defined.")]
                 pub fn $method(&self) -> Option<DefId> {
@@ -133,15 +116,6 @@ macro_rules! language_item_table {
                 }
             )*
         }
-
-        /// A mapping from the name of the lang item to its order and the form it must be of.
-        pub static ITEM_REFS: LazyLock<FxIndexMap<Symbol, (usize, Target)>> = LazyLock::new(|| {
-            let mut item_refs = FxIndexMap::default();
-            $( item_refs.insert($module::$name, (LangItem::$variant as usize, $target)); )*
-            item_refs
-        });
-
-// End of the macro
     }
 }
 
@@ -152,14 +126,12 @@ impl<CTX> HashStable<CTX> for LangItem {
 }
 
 /// Extracts the first `lang = "$name"` out of a list of attributes.
-/// The attributes `#[panic_handler]` and `#[alloc_error_handler]`
-/// are also extracted out when found.
+/// The `#[panic_handler]` attribute is also extracted out when found.
 pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     attrs.iter().find_map(|attr| {
         Some(match attr {
             _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span),
             _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span),
-            _ if attr.has_name(sym::alloc_error_handler) => (sym::oom, attr.span),
             _ => return None,
         })
     })
@@ -196,30 +168,30 @@ language_item_table! {
     TransmuteOpts,           sym::transmute_opts,      transmute_opts,             Target::Struct,         GenericRequirement::Exact(0);
     TransmuteTrait,          sym::transmute_trait,     transmute_trait,            Target::Trait,          GenericRequirement::Exact(3);
 
-    Add(Op),                 sym::add,                 add_trait,                  Target::Trait,          GenericRequirement::Exact(1);
-    Sub(Op),                 sym::sub,                 sub_trait,                  Target::Trait,          GenericRequirement::Exact(1);
-    Mul(Op),                 sym::mul,                 mul_trait,                  Target::Trait,          GenericRequirement::Exact(1);
-    Div(Op),                 sym::div,                 div_trait,                  Target::Trait,          GenericRequirement::Exact(1);
-    Rem(Op),                 sym::rem,                 rem_trait,                  Target::Trait,          GenericRequirement::Exact(1);
-    Neg(Op),                 sym::neg,                 neg_trait,                  Target::Trait,          GenericRequirement::Exact(0);
-    Not(Op),                 sym::not,                 not_trait,                  Target::Trait,          GenericRequirement::Exact(0);
-    BitXor(Op),              sym::bitxor,              bitxor_trait,               Target::Trait,          GenericRequirement::Exact(1);
-    BitAnd(Op),              sym::bitand,              bitand_trait,               Target::Trait,          GenericRequirement::Exact(1);
-    BitOr(Op),               sym::bitor,               bitor_trait,                Target::Trait,          GenericRequirement::Exact(1);
-    Shl(Op),                 sym::shl,                 shl_trait,                  Target::Trait,          GenericRequirement::Exact(1);
-    Shr(Op),                 sym::shr,                 shr_trait,                  Target::Trait,          GenericRequirement::Exact(1);
-    AddAssign(Op),           sym::add_assign,          add_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
-    SubAssign(Op),           sym::sub_assign,          sub_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
-    MulAssign(Op),           sym::mul_assign,          mul_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
-    DivAssign(Op),           sym::div_assign,          div_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
-    RemAssign(Op),           sym::rem_assign,          rem_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
-    BitXorAssign(Op),        sym::bitxor_assign,       bitxor_assign_trait,        Target::Trait,          GenericRequirement::Exact(1);
-    BitAndAssign(Op),        sym::bitand_assign,       bitand_assign_trait,        Target::Trait,          GenericRequirement::Exact(1);
-    BitOrAssign(Op),         sym::bitor_assign,        bitor_assign_trait,         Target::Trait,          GenericRequirement::Exact(1);
-    ShlAssign(Op),           sym::shl_assign,          shl_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
-    ShrAssign(Op),           sym::shr_assign,          shr_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
-    Index(Op),               sym::index,               index_trait,                Target::Trait,          GenericRequirement::Exact(1);
-    IndexMut(Op),            sym::index_mut,           index_mut_trait,            Target::Trait,          GenericRequirement::Exact(1);
+    Add,                     sym::add,                 add_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    Sub,                     sym::sub,                 sub_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    Mul,                     sym::mul,                 mul_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    Div,                     sym::div,                 div_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    Rem,                     sym::rem,                 rem_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    Neg,                     sym::neg,                 neg_trait,                  Target::Trait,          GenericRequirement::Exact(0);
+    Not,                     sym::not,                 not_trait,                  Target::Trait,          GenericRequirement::Exact(0);
+    BitXor,                  sym::bitxor,              bitxor_trait,               Target::Trait,          GenericRequirement::Exact(1);
+    BitAnd,                  sym::bitand,              bitand_trait,               Target::Trait,          GenericRequirement::Exact(1);
+    BitOr,                   sym::bitor,               bitor_trait,                Target::Trait,          GenericRequirement::Exact(1);
+    Shl,                     sym::shl,                 shl_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    Shr,                     sym::shr,                 shr_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    AddAssign,               sym::add_assign,          add_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    SubAssign,               sym::sub_assign,          sub_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    MulAssign,               sym::mul_assign,          mul_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    DivAssign,               sym::div_assign,          div_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    RemAssign,               sym::rem_assign,          rem_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    BitXorAssign,            sym::bitxor_assign,       bitxor_assign_trait,        Target::Trait,          GenericRequirement::Exact(1);
+    BitAndAssign,            sym::bitand_assign,       bitand_assign_trait,        Target::Trait,          GenericRequirement::Exact(1);
+    BitOrAssign,             sym::bitor_assign,        bitor_assign_trait,         Target::Trait,          GenericRequirement::Exact(1);
+    ShlAssign,               sym::shl_assign,          shl_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    ShrAssign,               sym::shr_assign,          shr_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    Index,                   sym::index,               index_trait,                Target::Trait,          GenericRequirement::Exact(1);
+    IndexMut,                sym::index_mut,           index_mut_trait,            Target::Trait,          GenericRequirement::Exact(1);
 
     UnsafeCell,              sym::unsafe_cell,         unsafe_cell_type,           Target::Struct,         GenericRequirement::None;
     VaList,                  sym::va_list,             va_list,                    Target::Struct,         GenericRequirement::None;
@@ -229,9 +201,9 @@ language_item_table! {
     DerefTarget,             sym::deref_target,        deref_target,               Target::AssocTy,        GenericRequirement::None;
     Receiver,                sym::receiver,            receiver_trait,             Target::Trait,          GenericRequirement::None;
 
-    Fn(Fn),                  kw::Fn,                   fn_trait,                   Target::Trait,          GenericRequirement::Exact(1);
-    FnMut(Fn),               sym::fn_mut,              fn_mut_trait,               Target::Trait,          GenericRequirement::Exact(1);
-    FnOnce(Fn),              sym::fn_once,             fn_once_trait,              Target::Trait,          GenericRequirement::Exact(1);
+    Fn,                      kw::Fn,                   fn_trait,                   Target::Trait,          GenericRequirement::Exact(1);
+    FnMut,                   sym::fn_mut,              fn_mut_trait,               Target::Trait,          GenericRequirement::Exact(1);
+    FnOnce,                  sym::fn_once,             fn_once_trait,              Target::Trait,          GenericRequirement::Exact(1);
 
     FnOnceOutput,            sym::fn_once_output,      fn_once_output,             Target::AssocTy,        GenericRequirement::None;
 
@@ -241,8 +213,8 @@ language_item_table! {
     Unpin,                   sym::unpin,               unpin_trait,                Target::Trait,          GenericRequirement::None;
     Pin,                     sym::pin,                 pin_type,                   Target::Struct,         GenericRequirement::None;
 
-    PartialEq(Op),           sym::eq,                  eq_trait,                   Target::Trait,          GenericRequirement::Exact(1);
-    PartialOrd(Op),          sym::partial_ord,         partial_ord_trait,          Target::Trait,          GenericRequirement::Exact(1);
+    PartialEq,               sym::eq,                  eq_trait,                   Target::Trait,          GenericRequirement::Exact(1);
+    PartialOrd,              sym::partial_ord,         partial_ord_trait,          Target::Trait,          GenericRequirement::Exact(1);
 
     // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
     // various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.
@@ -266,7 +238,6 @@ language_item_table! {
     ExchangeMalloc,          sym::exchange_malloc,     exchange_malloc_fn,         Target::Fn,             GenericRequirement::None;
     BoxFree,                 sym::box_free,            box_free_fn,                Target::Fn,             GenericRequirement::Minimum(1);
     DropInPlace,             sym::drop_in_place,       drop_in_place_fn,           Target::Fn,             GenericRequirement::Minimum(1);
-    Oom,                     sym::oom,                 oom,                        Target::Fn,             GenericRequirement::None;
     AllocLayout,             sym::alloc_layout,        alloc_layout,               Target::Struct,         GenericRequirement::None;
 
     Start,                   sym::start,               start_fn,                   Target::Fn,             GenericRequirement::Exact(1);
@@ -338,3 +309,34 @@ pub enum GenericRequirement {
     Minimum(usize),
     Exact(usize),
 }
+
+pub static FN_TRAITS: &'static [LangItem] = &[LangItem::Fn, LangItem::FnMut, LangItem::FnOnce];
+
+pub static OPERATORS: &'static [LangItem] = &[
+    LangItem::Add,
+    LangItem::Sub,
+    LangItem::Mul,
+    LangItem::Div,
+    LangItem::Rem,
+    LangItem::Neg,
+    LangItem::Not,
+    LangItem::BitXor,
+    LangItem::BitAnd,
+    LangItem::BitOr,
+    LangItem::Shl,
+    LangItem::Shr,
+    LangItem::AddAssign,
+    LangItem::SubAssign,
+    LangItem::MulAssign,
+    LangItem::DivAssign,
+    LangItem::RemAssign,
+    LangItem::BitXorAssign,
+    LangItem::BitAndAssign,
+    LangItem::BitOrAssign,
+    LangItem::ShlAssign,
+    LangItem::ShrAssign,
+    LangItem::Index,
+    LangItem::IndexMut,
+    LangItem::PartialEq,
+    LangItem::PartialOrd,
+];
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 1c4aa420c9b..1c55cd8fee8 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -5,10 +5,10 @@
 #![feature(associated_type_defaults)]
 #![feature(closure_track_caller)]
 #![feature(const_btree_len)]
-#![feature(once_cell)]
 #![feature(min_specialization)]
 #![feature(never_type)]
 #![feature(rustc_attrs)]
+#![feature(variant_count)]
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 06b7a65662e..23423e8f3b3 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -49,7 +49,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ItemId {
 
     #[inline]
     fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
-        self.def_id.def_id.to_stable_hash_key(hcx)
+        self.owner_id.def_id.to_stable_hash_key(hcx)
     }
 }
 
@@ -58,7 +58,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for TraitItemId {
 
     #[inline]
     fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
-        self.def_id.def_id.to_stable_hash_key(hcx)
+        self.owner_id.def_id.to_stable_hash_key(hcx)
     }
 }
 
@@ -67,7 +67,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ImplItemId {
 
     #[inline]
     fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
-        self.def_id.def_id.to_stable_hash_key(hcx)
+        self.owner_id.def_id.to_stable_hash_key(hcx)
     }
 }
 
@@ -76,7 +76,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ForeignItemId
 
     #[inline]
     fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
-        self.def_id.def_id.to_stable_hash_key(hcx)
+        self.owner_id.def_id.to_stable_hash_key(hcx)
     }
 }
 
diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs
index da9c9c1216e..0cc50c6dd85 100644
--- a/compiler/rustc_hir/src/weak_lang_items.rs
+++ b/compiler/rustc_hir/src/weak_lang_items.rs
@@ -1,53 +1,30 @@
 //! Validity checking for weak lang items
 
-use crate::def_id::DefId;
-use crate::{lang_items, LangItem, LanguageItems};
+use crate::LangItem;
 
-use rustc_ast as ast;
-use rustc_data_structures::fx::FxIndexMap;
 use rustc_span::symbol::{sym, Symbol};
 
-use std::sync::LazyLock;
-
 macro_rules! weak_lang_items {
-    ($($name:ident, $item:ident, $sym:ident;)*) => (
-
-pub static WEAK_ITEMS_REFS: LazyLock<FxIndexMap<Symbol, LangItem>> = LazyLock::new(|| {
-    let mut map = FxIndexMap::default();
-    $(map.insert(sym::$name, LangItem::$item);)*
-    map
-});
-
-pub static WEAK_ITEMS_SYMBOLS: LazyLock<FxIndexMap<LangItem, Symbol>> = LazyLock::new(|| {
-    let mut map = FxIndexMap::default();
-    $(map.insert(LangItem::$item, sym::$sym);)*
-    map
-});
-
-pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol>
-{
-    lang_items::extract(attrs).and_then(|(name, _)| {
-        $(if name == sym::$name {
-            Some(sym::$sym)
-        } else)* {
-            None
+    ($($item:ident, $sym:ident;)*) => {
+        pub static WEAK_LANG_ITEMS: &[LangItem] = &[$(LangItem::$item,)*];
+
+        impl LangItem {
+            pub fn is_weak(self) -> bool {
+                matches!(self, $(LangItem::$item)|*)
+            }
+
+            pub fn link_name(self) -> Option<Symbol> {
+                match self {
+                    $( LangItem::$item => Some(sym::$sym),)*
+                    _ => None,
+                }
+            }
         }
-    })
-}
-
-impl LanguageItems {
-    pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool {
-        let did = Some(item_def_id);
-
-        $(self.$name() == did)||*
     }
 }
 
-) }
-
 weak_lang_items! {
-    panic_impl,         PanicImpl,          rust_begin_unwind;
-    eh_personality,     EhPersonality,      rust_eh_personality;
-    eh_catch_typeinfo,  EhCatchTypeinfo,    rust_eh_catch_typeinfo;
-    oom,                Oom,                rust_oom;
+    PanicImpl,          rust_begin_unwind;
+    EhPersonality,      rust_eh_personality;
+    EhCatchTypeinfo,    rust_eh_catch_typeinfo;
 }
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index a9152bdc597..e6465d641f1 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -177,11 +177,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .all_traits()
             .filter(|trait_def_id| {
                 let viz = self.tcx().visibility(*trait_def_id);
-                if let Some(def_id) = self.item_def_id() {
-                    viz.is_accessible_from(def_id, self.tcx())
-                } else {
-                    viz.is_visible_locally()
-                }
+                let def_id = self.item_def_id();
+                viz.is_accessible_from(def_id, self.tcx())
             })
             .collect();
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 6e373e41b4c..7747ae14a24 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -23,7 +23,6 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{walk_generics, Visitor as _};
-use rustc_hir::lang_items::LangItem;
 use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
 use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
@@ -36,7 +35,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::astconv_object_safety_violations;
@@ -55,7 +54,7 @@ pub struct PathSeg(pub DefId, pub usize);
 pub trait AstConv<'tcx> {
     fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
 
-    fn item_def_id(&self) -> Option<DefId>;
+    fn item_def_id(&self) -> DefId;
 
     /// Returns predicates in scope of the form `X: Foo<T>`, where `X`
     /// is a type parameter `X` with the given id `def_id` and T
@@ -275,6 +274,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             item_segment.args(),
             item_segment.infer_args,
             None,
+            None,
         );
         if let Some(b) = item_segment.args().bindings.first() {
             Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
@@ -324,6 +324,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         generic_args: &'a hir::GenericArgs<'_>,
         infer_args: bool,
         self_ty: Option<Ty<'tcx>>,
+        constness: Option<ty::BoundConstness>,
     ) -> (SubstsRef<'tcx>, GenericArgCountResult) {
         // If the type is parameterized by this region, then replace this
         // region with the current anon region binding (in other words,
@@ -499,6 +500,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     }
                     GenericParamDefKind::Const { has_default } => {
                         let ty = tcx.at(self.span).type_of(param.def_id);
+                        if ty.references_error() {
+                            return tcx.const_error(ty).into();
+                        }
                         if !infer_args && has_default {
                             tcx.bound_const_param_default(param.def_id)
                                 .subst(tcx, substs.unwrap())
@@ -534,6 +538,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             &mut substs_ctx,
         );
 
+        if let Some(ty::BoundConstness::ConstIfConst) = constness
+            && generics.has_self && !tcx.has_attr(def_id, sym::const_trait)
+        {
+            tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } );
+        }
+
         (substs, arg_count)
     }
 
@@ -582,7 +592,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         assoc_bindings
     }
 
-    pub(crate) fn create_substs_for_associated_item(
+    pub fn create_substs_for_associated_item(
         &self,
         span: Span,
         item_def_id: DefId,
@@ -601,6 +611,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             item_segment.args(),
             item_segment.infer_args,
             None,
+            None,
         );
 
         if let Some(b) = item_segment.args().bindings.first() {
@@ -620,6 +631,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         &self,
         trait_ref: &hir::TraitRef<'_>,
         self_ty: Ty<'tcx>,
+        constness: ty::BoundConstness,
     ) -> ty::TraitRef<'tcx> {
         self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
 
@@ -629,6 +641,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             self_ty,
             trait_ref.path.segments.last().unwrap(),
             true,
+            Some(constness),
         )
     }
 
@@ -655,6 +668,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             args,
             infer_args,
             Some(self_ty),
+            Some(constness),
         );
 
         let tcx = self.tcx();
@@ -680,6 +694,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 speculative,
                 &mut dup_bindings,
                 binding_span.unwrap_or(binding.span),
+                constness,
             );
             // Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
         }
@@ -783,6 +798,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         self_ty: Ty<'tcx>,
         trait_segment: &hir::PathSegment<'_>,
         is_impl: bool,
+        constness: Option<ty::BoundConstness>,
     ) -> ty::TraitRef<'tcx> {
         let (substs, _) = self.create_substs_for_ast_trait_ref(
             span,
@@ -790,6 +806,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             self_ty,
             trait_segment,
             is_impl,
+            constness,
         );
         if let Some(b) = trait_segment.args().bindings.first() {
             Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
@@ -805,6 +822,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         self_ty: Ty<'tcx>,
         trait_segment: &'a hir::PathSegment<'a>,
         is_impl: bool,
+        constness: Option<ty::BoundConstness>,
     ) -> (SubstsRef<'tcx>, GenericArgCountResult) {
         self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
 
@@ -816,6 +834,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             trait_segment.args(),
             trait_segment.infer_args,
             Some(self_ty),
+            constness,
         )
     }
 
@@ -867,9 +886,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
         }
 
-        let sized_def_id = tcx.lang_items().require(LangItem::Sized);
+        let sized_def_id = tcx.lang_items().sized_trait();
         match (&sized_def_id, unbound) {
-            (Ok(sized_def_id), Some(tpb))
+            (Some(sized_def_id), Some(tpb))
                 if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) =>
             {
                 // There was in fact a `?Sized` bound, return without doing anything
@@ -889,7 +908,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // There was no `?Sized` bound; add implicitly sized if `Sized` is available.
             }
         }
-        if sized_def_id.is_err() {
+        if sized_def_id.is_none() {
             // No lang item for `Sized`, so we can't add it as a bound.
             return;
         }
@@ -1027,6 +1046,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         speculative: bool,
         dup_bindings: &mut FxHashMap<DefId, Span>,
         path_span: Span,
+        constness: ty::BoundConstness,
     ) -> Result<(), ErrorGuaranteed> {
         // Given something like `U: SomeTrait<T = X>`, we want to produce a
         // predicate like `<U as SomeTrait>::T = X`. This is somewhat
@@ -1122,10 +1142,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 trait_ref.substs,
             );
 
-            debug!(
-                "add_predicates_for_ast_type_binding: substs for trait-ref and assoc_item: {:?}",
-                substs_trait_ref_and_assoc_item
-            );
+            debug!(?substs_trait_ref_and_assoc_item);
 
             ty::ProjectionTy {
                 item_def_id: assoc_item.def_id,
@@ -1146,8 +1163,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     tcx.collect_constrained_late_bound_regions(&projection_ty);
                 let late_bound_in_ty =
                     tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
-                debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
-                debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
+                debug!(?late_bound_in_trait_ref);
+                debug!(?late_bound_in_ty);
 
                 // FIXME: point at the type params that don't have appropriate lifetimes:
                 // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
@@ -1648,6 +1665,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
     // Checks that `bounds` contains exactly one element and reports appropriate
     // errors otherwise.
+    #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, is_equality), ret)]
     fn one_bound_for_assoc_type<I>(
         &self,
         all_candidates: impl Fn() -> I,
@@ -1677,10 +1695,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 return Err(reported);
             }
         };
-        debug!("one_bound_for_assoc_type: bound = {:?}", bound);
+        debug!(?bound);
 
         if let Some(bound2) = next_cand {
-            debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
+            debug!(?bound2);
 
             let is_equality = is_equality();
             let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
@@ -1776,6 +1794,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     // parameter or `Self`.
     // NOTE: When this function starts resolving `Trait::AssocTy` successfully
     // it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
+    #[instrument(level = "debug", skip(self, hir_ref_id, span, qself, assoc_segment), fields(assoc_ident=?assoc_segment.ident), ret)]
     pub fn associated_path_to_ty(
         &self,
         hir_ref_id: hir::HirId,
@@ -1793,8 +1812,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             Res::Err
         };
 
-        debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
-
         // Check if we have an enum variant.
         let mut variant_resolution = None;
         if let ty::Adt(adt_def, _) = qself_ty.kind() {
@@ -1962,7 +1979,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     }
 
                     err.emit()
-                } else if let Some(reported) = qself_ty.error_reported() {
+                } else if let Err(reported) = qself_ty.error_reported() {
                     reported
                 } else {
                     // Don't print `TyErr` to the user.
@@ -2050,6 +2067,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         item_def_id: DefId,
         trait_segment: &hir::PathSegment<'_>,
         item_segment: &hir::PathSegment<'_>,
+        constness: ty::BoundConstness,
     ) -> Ty<'tcx> {
         let tcx = self.tcx();
 
@@ -2064,17 +2082,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
             debug!("qpath_to_ty: self.item_def_id()={:?}", def_id);
 
-            let parent_def_id = def_id
-                .and_then(|def_id| {
-                    def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
-                })
+            let parent_def_id = def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
                 .map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id());
 
             debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id);
 
             // If the trait in segment is the same as the trait defining the item,
             // use the `<Self as ..>` syntax in the error.
-            let is_part_of_self_trait_constraints = def_id == Some(trait_def_id);
+            let is_part_of_self_trait_constraints = def_id == trait_def_id;
             let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
 
             let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
@@ -2094,8 +2109,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         debug!("qpath_to_ty: self_type={:?}", self_ty);
 
-        let trait_ref =
-            self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
+        let trait_ref = self.ast_path_to_mono_trait_ref(
+            span,
+            trait_def_id,
+            self_ty,
+            trait_segment,
+            false,
+            Some(constness),
+        );
 
         let item_substs = self.create_substs_for_associated_item(
             span,
@@ -2534,12 +2555,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             Res::Def(DefKind::AssocTy, def_id) => {
                 debug_assert!(path.segments.len() >= 2);
                 self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {});
+                // HACK: until we support `<Type as ~const Trait>`, assume all of them are.
+                let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
+                    ty::BoundConstness::ConstIfConst
+                } else {
+                    ty::BoundConstness::NotConst
+                };
                 self.qpath_to_ty(
                     span,
                     opt_self_ty,
                     def_id,
                     &path.segments[path.segments.len() - 2],
                     path.segments.last().unwrap(),
+                    constness,
                 )
             }
             Res::PrimTy(prim_ty) => {
@@ -2632,7 +2660,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
                 let opaque_ty = tcx.hir().item(item_id);
-                let def_id = item_id.def_id.to_def_id();
+                let def_id = item_id.owner_id.to_def_id();
 
                 match opaque_ty.kind {
                     hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
@@ -2658,6 +2686,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     &GenericArgs::none(),
                     true,
                     None,
+                    None,
                 );
                 EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
                     .subst(tcx, substs)
@@ -2766,6 +2795,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         }
     }
 
+    #[instrument(level = "debug", skip(self, hir_id, unsafety, abi, decl, generics, hir_ty), ret)]
     pub fn ty_of_fn(
         &self,
         hir_id: hir::HirId,
@@ -2775,8 +2805,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         generics: Option<&hir::Generics<'_>>,
         hir_ty: Option<&hir::Ty<'_>>,
     ) -> ty::PolyFnSig<'tcx> {
-        debug!("ty_of_fn");
-
         let tcx = self.tcx();
         let bound_vars = tcx.late_bound_vars(hir_id);
         debug!(?bound_vars);
@@ -2826,7 +2854,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(),
         };
 
-        debug!("ty_of_fn: output_ty={:?}", output_ty);
+        debug!(?output_ty);
 
         let fn_ty = tcx.mk_fn_sig(input_tys.into_iter(), output_ty, decl.c_variadic, unsafety, abi);
         let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
@@ -2903,8 +2931,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
                 hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
 
-        let trait_ref =
-            self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));
+        let trait_ref = self.instantiate_mono_trait_ref(
+            i.of_trait.as_ref()?,
+            self.ast_ty_to_ty(i.self_ty),
+            ty::BoundConstness::NotConst,
+        );
 
         let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
             tcx,
@@ -3051,24 +3082,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     .map_or(false, |s| s.trim_end().ends_with('<'));
 
             let is_global = poly_trait_ref.trait_ref.path.is_global();
-            let sugg = Vec::from_iter([
-                (
-                    self_ty.span.shrink_to_lo(),
-                    format!(
-                        "{}dyn {}",
-                        if needs_bracket { "<" } else { "" },
-                        if is_global { "(" } else { "" },
-                    ),
+
+            let mut sugg = Vec::from_iter([(
+                self_ty.span.shrink_to_lo(),
+                format!(
+                    "{}dyn {}",
+                    if needs_bracket { "<" } else { "" },
+                    if is_global { "(" } else { "" },
                 ),
-                (
+            )]);
+
+            if is_global || needs_bracket {
+                sugg.push((
                     self_ty.span.shrink_to_hi(),
                     format!(
                         "{}{}",
                         if is_global { ")" } else { "" },
                         if needs_bracket { ">" } else { "" },
                     ),
-                ),
-            ]);
+                ));
+            }
+
             if self_ty.span.edition() >= Edition::Edition2021 {
                 let msg = "trait objects must include the `dyn` keyword";
                 let label = "add `dyn` keyword before this trait";
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 7cee9779c5f..133bbd52b91 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,19 +1,16 @@
 use crate::check::intrinsicck::InlineAsmCtxt;
 
-use super::coercion::CoerceMany;
 use super::compare_method::check_type_bounds;
 use super::compare_method::{compare_impl_method, compare_ty_impl};
 use super::*;
 use rustc_attr as attr;
 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ItemKind, Node, PathSegment};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
@@ -34,7 +31,7 @@ use rustc_trait_selection::traits::{self, ObligationCtxt};
 
 use std::ops::ControlFlow;
 
-pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
+pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
     match tcx.sess.target.is_abi_supported(abi) {
         Some(true) => (),
         Some(false) => {
@@ -69,313 +66,6 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab
     }
 }
 
-/// Helper used for fns and closures. Does the grungy work of checking a function
-/// body and returns the function context used for that purpose, since in the case of a fn item
-/// there is still a bit more to do.
-///
-/// * ...
-/// * inherited: other fields inherited from the enclosing fn (if any)
-#[instrument(skip(inherited, body), level = "debug")]
-pub(super) fn check_fn<'a, 'tcx>(
-    inherited: &'a Inherited<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    fn_sig: ty::FnSig<'tcx>,
-    decl: &'tcx hir::FnDecl<'tcx>,
-    fn_id: hir::HirId,
-    body: &'tcx hir::Body<'tcx>,
-    can_be_generator: Option<hir::Movability>,
-    return_type_pre_known: bool,
-) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
-    // Create the function context. This is either derived from scratch or,
-    // in the case of closures, based on the outer context.
-    let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
-    fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
-    fcx.return_type_pre_known = return_type_pre_known;
-
-    let tcx = fcx.tcx;
-    let hir = tcx.hir();
-
-    let declared_ret_ty = fn_sig.output();
-
-    let ret_ty =
-        fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
-            declared_ret_ty,
-            body.value.hir_id,
-            decl.output.span(),
-            param_env,
-        ));
-    // If we replaced declared_ret_ty with infer vars, then we must be inferring
-    // an opaque type, so set a flag so we can improve diagnostics.
-    fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
-
-    fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
-
-    let span = body.value.span;
-
-    fn_maybe_err(tcx, span, fn_sig.abi);
-
-    if fn_sig.abi == Abi::RustCall {
-        let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
-
-        let err = || {
-            let item = match tcx.hir().get(fn_id) {
-                Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
-                Node::ImplItem(hir::ImplItem {
-                    kind: hir::ImplItemKind::Fn(header, ..), ..
-                }) => Some(header),
-                Node::TraitItem(hir::TraitItem {
-                    kind: hir::TraitItemKind::Fn(header, ..),
-                    ..
-                }) => Some(header),
-                // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
-                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
-                node => bug!("Item being checked wasn't a function/closure: {:?}", node),
-            };
-
-            if let Some(header) = item {
-                tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
-            }
-        };
-
-        if fn_sig.inputs().len() != expected_args {
-            err()
-        } else {
-            // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
-            //   This will probably require wide-scale changes to support a TupleKind obligation
-            //   We can't resolve this without knowing the type of the param
-            if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
-                err()
-            }
-        }
-    }
-
-    if body.generator_kind.is_some() && can_be_generator.is_some() {
-        let yield_ty = fcx
-            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
-        fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
-
-        // Resume type defaults to `()` if the generator has no argument.
-        let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
-
-        fcx.resume_yield_tys = Some((resume_ty, yield_ty));
-    }
-
-    GatherLocalsVisitor::new(&fcx).visit_body(body);
-
-    // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
-    // (as it's created inside the body itself, not passed in from outside).
-    let maybe_va_list = if fn_sig.c_variadic {
-        let span = body.params.last().unwrap().span;
-        let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
-        let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
-
-        Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
-    } else {
-        None
-    };
-
-    // Add formal parameters.
-    let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
-    let inputs_fn = fn_sig.inputs().iter().copied();
-    for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
-        // Check the pattern.
-        let ty_span = try { inputs_hir?.get(idx)?.span };
-        fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
-
-        // Check that argument is Sized.
-        // The check for a non-trivial pattern is a hack to avoid duplicate warnings
-        // for simple cases like `fn foo(x: Trait)`,
-        // where we would error once on the parameter as a whole, and once on the binding `x`.
-        if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
-            fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
-        }
-
-        fcx.write_ty(param.hir_id, param_ty);
-    }
-
-    inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
-
-    fcx.in_tail_expr = true;
-    if let ty::Dynamic(..) = declared_ret_ty.kind() {
-        // FIXME: We need to verify that the return type is `Sized` after the return expression has
-        // been evaluated so that we have types available for all the nodes being returned, but that
-        // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
-        // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
-        // while keeping the current ordering we will ignore the tail expression's type because we
-        // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
-        // because we will trigger "unreachable expression" lints unconditionally.
-        // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
-        // case that a newcomer might make, returning a bare trait, and in that case we populate
-        // the tail expression's type so that the suggestion will be correct, but ignore all other
-        // possible cases.
-        fcx.check_expr(&body.value);
-        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
-    } else {
-        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
-        fcx.check_return_expr(&body.value, false);
-    }
-    fcx.in_tail_expr = false;
-
-    // We insert the deferred_generator_interiors entry after visiting the body.
-    // This ensures that all nested generators appear before the entry of this generator.
-    // resolve_generator_interiors relies on this property.
-    let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
-        let interior = fcx
-            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
-        fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
-
-        let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
-        Some(GeneratorTypes {
-            resume_ty,
-            yield_ty,
-            interior,
-            movability: can_be_generator.unwrap(),
-        })
-    } else {
-        None
-    };
-
-    // Finalize the return check by taking the LUB of the return types
-    // we saw and assigning it to the expected return type. This isn't
-    // really expected to fail, since the coercions would have failed
-    // earlier when trying to find a LUB.
-    let coercion = fcx.ret_coercion.take().unwrap().into_inner();
-    let mut actual_return_ty = coercion.complete(&fcx);
-    debug!("actual_return_ty = {:?}", actual_return_ty);
-    if let ty::Dynamic(..) = declared_ret_ty.kind() {
-        // We have special-cased the case where the function is declared
-        // `-> dyn Foo` and we don't actually relate it to the
-        // `fcx.ret_coercion`, so just substitute a type variable.
-        actual_return_ty =
-            fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
-        debug!("actual_return_ty replaced with {:?}", actual_return_ty);
-    }
-
-    // HACK(oli-obk, compiler-errors): We should be comparing this against
-    // `declared_ret_ty`, but then anything uninferred would be inferred to
-    // the opaque type itself. That again would cause writeback to assume
-    // we have a recursive call site and do the sadly stabilized fallback to `()`.
-    fcx.demand_suptype(span, ret_ty, actual_return_ty);
-
-    // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
-    if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
-        && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
-    {
-        check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
-    }
-
-    // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
-    if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
-        && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
-    {
-        check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
-    }
-
-    (fcx, gen_ty)
-}
-
-fn check_panic_info_fn(
-    tcx: TyCtxt<'_>,
-    fn_id: LocalDefId,
-    fn_sig: ty::FnSig<'_>,
-    decl: &hir::FnDecl<'_>,
-    declared_ret_ty: Ty<'_>,
-) {
-    let Some(panic_info_did) = tcx.lang_items().panic_info() else {
-        tcx.sess.err("language item required, but not found: `panic_info`");
-        return;
-    };
-
-    if *declared_ret_ty.kind() != ty::Never {
-        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
-    }
-
-    let inputs = fn_sig.inputs();
-    if inputs.len() != 1 {
-        tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
-        return;
-    }
-
-    let arg_is_panic_info = match *inputs[0].kind() {
-        ty::Ref(region, ty, mutbl) => match *ty.kind() {
-            ty::Adt(ref adt, _) => {
-                adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
-            }
-            _ => false,
-        },
-        _ => false,
-    };
-
-    if !arg_is_panic_info {
-        tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
-    }
-
-    let DefKind::Fn = tcx.def_kind(fn_id) else {
-        let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "should be a function");
-        return;
-    };
-
-    let generic_counts = tcx.generics_of(fn_id).own_counts();
-    if generic_counts.types != 0 {
-        let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "should have no type parameters");
-    }
-    if generic_counts.consts != 0 {
-        let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "should have no const parameters");
-    }
-}
-
-fn check_alloc_error_fn(
-    tcx: TyCtxt<'_>,
-    fn_id: LocalDefId,
-    fn_sig: ty::FnSig<'_>,
-    decl: &hir::FnDecl<'_>,
-    declared_ret_ty: Ty<'_>,
-) {
-    let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
-        tcx.sess.err("language item required, but not found: `alloc_layout`");
-        return;
-    };
-
-    if *declared_ret_ty.kind() != ty::Never {
-        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
-    }
-
-    let inputs = fn_sig.inputs();
-    if inputs.len() != 1 {
-        tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
-        return;
-    }
-
-    let arg_is_alloc_layout = match inputs[0].kind() {
-        ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
-        _ => false,
-    };
-
-    if !arg_is_alloc_layout {
-        tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
-    }
-
-    let DefKind::Fn = tcx.def_kind(fn_id) else {
-        let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
-        return;
-    };
-
-    let generic_counts = tcx.generics_of(fn_id).own_counts();
-    if generic_counts.types != 0 {
-        let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
-    }
-    if generic_counts.consts != 0 {
-        let span = tcx.def_span(fn_id);
-        tcx.sess
-            .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
-    }
-}
-
 fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let def = tcx.adt_def(def_id);
     let span = tcx.def_span(def_id);
@@ -385,7 +75,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         check_simd(tcx, span, def_id);
     }
 
-    check_transparent(tcx, span, def);
+    check_transparent(tcx, def);
     check_packed(tcx, span, def);
 }
 
@@ -393,7 +83,7 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let def = tcx.adt_def(def_id);
     let span = tcx.def_span(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
-    check_transparent(tcx, span, def);
+    check_transparent(tcx, def);
     check_union_fields(tcx, span, def_id);
     check_packed(tcx, span, def);
 }
@@ -424,7 +114,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
                 _ => {
                     // Fallback case: allow `ManuallyDrop` and things that are `Copy`.
                     ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
-                        || ty.is_copy_modulo_regions(tcx.at(span), param_env)
+                        || ty.is_copy_modulo_regions(tcx, param_env)
                 }
             }
         }
@@ -537,17 +227,17 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
         return;
     }
 
-    let substs = InternalSubsts::identity_for_item(tcx, item.def_id.to_def_id());
-    let span = tcx.def_span(item.def_id.def_id);
+    let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id());
+    let span = tcx.def_span(item.owner_id.def_id);
 
-    check_opaque_for_inheriting_lifetimes(tcx, item.def_id.def_id, span);
-    if tcx.type_of(item.def_id.def_id).references_error() {
+    check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
+    if tcx.type_of(item.owner_id.def_id).references_error() {
         return;
     }
-    if check_opaque_for_cycles(tcx, item.def_id.def_id, substs, span, &origin).is_err() {
+    if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() {
         return;
     }
-    check_opaque_meets_bounds(tcx, item.def_id.def_id, substs, span, &origin);
+    check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
 }
 /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
 /// in "inheriting lifetimes".
@@ -732,8 +422,6 @@ fn check_opaque_meets_bounds<'tcx>(
     span: Span,
     origin: &hir::OpaqueTyOrigin,
 ) {
-    let hidden_type = tcx.bound_type_of(def_id.to_def_id()).subst(tcx, substs);
-
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let defining_use_anchor = match *origin {
         hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
@@ -748,14 +436,26 @@ fn check_opaque_meets_bounds<'tcx>(
     let ocx = ObligationCtxt::new(&infcx);
     let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
 
+    // `ReErased` regions appear in the "parent_substs" of closures/generators.
+    // We're ignoring them here and replacing them with fresh region variables.
+    // See tests in ui/type-alias-impl-trait/closure_{parent_substs,wf_outlives}.rs.
+    //
+    // FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it
+    // here rather than using ReErased.
+    let hidden_ty = tcx.bound_type_of(def_id.to_def_id()).subst(tcx, substs);
+    let hidden_ty = tcx.fold_regions(hidden_ty, |re, _dbi| match re.kind() {
+        ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
+        _ => re,
+    });
+
     let misc_cause = traits::ObligationCause::misc(span, hir_id);
 
-    match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
+    match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_ty) {
         Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
         Err(ty_err) => {
             tcx.sess.delay_span_bug(
                 span,
-                &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
+                &format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
             );
         }
     }
@@ -764,7 +464,7 @@ fn check_opaque_meets_bounds<'tcx>(
     // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
     // hidden type is well formed even without those bounds.
     let predicate =
-        ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())).to_predicate(tcx);
+        ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_ty.into())).to_predicate(tcx);
     ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
 
     // Check that all obligations are satisfied by the implementation's
@@ -792,25 +492,21 @@ fn check_opaque_meets_bounds<'tcx>(
 fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
     debug!(
         "check_item_type(it.def_id={:?}, it.name={})",
-        id.def_id,
-        tcx.def_path_str(id.def_id.to_def_id())
+        id.owner_id,
+        tcx.def_path_str(id.owner_id.to_def_id())
     );
     let _indenter = indenter();
-    match tcx.def_kind(id.def_id) {
+    match tcx.def_kind(id.owner_id) {
         DefKind::Static(..) => {
-            tcx.ensure().typeck(id.def_id.def_id);
-            maybe_check_static_with_link_section(tcx, id.def_id.def_id);
-            check_static_inhabited(tcx, id.def_id.def_id);
+            tcx.ensure().typeck(id.owner_id.def_id);
+            maybe_check_static_with_link_section(tcx, id.owner_id.def_id);
+            check_static_inhabited(tcx, id.owner_id.def_id);
         }
         DefKind::Const => {
-            tcx.ensure().typeck(id.def_id.def_id);
+            tcx.ensure().typeck(id.owner_id.def_id);
         }
         DefKind::Enum => {
-            let item = tcx.hir().item(id);
-            let hir::ItemKind::Enum(ref enum_definition, _) = item.kind else {
-                return;
-            };
-            check_enum(tcx, &enum_definition.variants, item.def_id.def_id);
+            check_enum(tcx, id.owner_id.def_id);
         }
         DefKind::Fn => {} // entirely within check_item_body
         DefKind::Impl => {
@@ -818,12 +514,12 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
             let hir::ItemKind::Impl(ref impl_) = it.kind else {
                 return;
             };
-            debug!("ItemKind::Impl {} with id {:?}", it.ident, it.def_id);
-            if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.def_id) {
+            debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id);
+            if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) {
                 check_impl_items_against_trait(
                     tcx,
                     it.span,
-                    it.def_id.def_id,
+                    it.owner_id.def_id,
                     impl_trait_ref,
                     &impl_.items,
                 );
@@ -845,15 +541,15 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
                         fn_maybe_err(tcx, item.ident.span, abi);
                     }
                     hir::TraitItemKind::Type(.., Some(default)) => {
-                        let assoc_item = tcx.associated_item(item.def_id);
+                        let assoc_item = tcx.associated_item(item.owner_id);
                         let trait_substs =
-                            InternalSubsts::identity_for_item(tcx, it.def_id.to_def_id());
+                            InternalSubsts::identity_for_item(tcx, it.owner_id.to_def_id());
                         let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
                             tcx,
                             assoc_item,
                             assoc_item,
                             default.span,
-                            ty::TraitRef { def_id: it.def_id.to_def_id(), substs: trait_substs },
+                            ty::TraitRef { def_id: it.owner_id.to_def_id(), substs: trait_substs },
                         );
                     }
                     _ => {}
@@ -861,16 +557,16 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
             }
         }
         DefKind::Struct => {
-            check_struct(tcx, id.def_id.def_id);
+            check_struct(tcx, id.owner_id.def_id);
         }
         DefKind::Union => {
-            check_union(tcx, id.def_id.def_id);
+            check_union(tcx, id.owner_id.def_id);
         }
         DefKind::OpaqueTy => {
             check_opaque(tcx, id);
         }
         DefKind::ImplTraitPlaceholder => {
-            let parent = tcx.impl_trait_in_trait_parent(id.def_id.to_def_id());
+            let parent = tcx.impl_trait_in_trait_parent(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(_)),
@@ -881,8 +577,8 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
             }
         }
         DefKind::TyAlias => {
-            let pty_ty = tcx.type_of(id.def_id);
-            let generics = tcx.generics_of(id.def_id);
+            let pty_ty = tcx.type_of(id.owner_id);
+            let generics = tcx.generics_of(id.owner_id);
             check_type_params_are_used(tcx, &generics, pty_ty);
         }
         DefKind::ForeignMod => {
@@ -904,7 +600,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
                 }
             } else {
                 for item in items {
-                    let def_id = item.id.def_id.def_id;
+                    let def_id = item.id.owner_id.def_id;
                     let generics = tcx.generics_of(def_id);
                     let own_counts = generics.own_counts();
                     if generics.params.len() - own_counts.lifetimes != 0 {
@@ -959,7 +655,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
 
 pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
     // an error would be reported if this fails.
-    let _ = traits::OnUnimplementedDirective::of_item(tcx, item.def_id.to_def_id());
+    let _ = traits::OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id());
 }
 
 pub(super) fn check_specialization_validity<'tcx>(
@@ -1046,7 +742,7 @@ fn check_impl_items_against_trait<'tcx>(
     let trait_def = tcx.trait_def(impl_trait_ref.def_id);
 
     for impl_item in impl_item_refs {
-        let ty_impl_item = tcx.associated_item(impl_item.id.def_id);
+        let ty_impl_item = tcx.associated_item(impl_item.id.owner_id);
         let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
             tcx.associated_item(trait_item_id)
         } else {
@@ -1058,7 +754,7 @@ fn check_impl_items_against_trait<'tcx>(
         match impl_item_full.kind {
             hir::ImplItemKind::Const(..) => {
                 let _ = tcx.compare_assoc_const_impl_item_with_trait_item((
-                    impl_item.id.def_id.def_id,
+                    impl_item.id.owner_id.def_id,
                     ty_impl_item.trait_item_def_id.unwrap(),
                 ));
             }
@@ -1326,7 +1022,7 @@ pub(super) fn check_packed_inner(
     None
 }
 
-pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtDef<'tcx>) {
+pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
     if !adt.repr().transparent() {
         return;
     }
@@ -1335,14 +1031,14 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
         feature_err(
             &tcx.sess.parse_sess,
             sym::transparent_unions,
-            sp,
+            tcx.def_span(adt.did()),
             "transparent unions are unstable",
         )
         .emit();
     }
 
     if adt.variants().len() != 1 {
-        bad_variant_count(tcx, adt, sp, adt.did());
+        bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());
         if adt.variants().is_empty() {
             // Don't bother checking the fields. No variants (and thus no fields) exist.
             return;
@@ -1403,7 +1099,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
         .filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None });
     let non_zst_count = non_zst_fields.clone().count();
     if non_zst_count >= 2 {
-        bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
+        bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
     }
     let incompatible_zst_fields =
         field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
@@ -1443,12 +1139,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
 }
 
 #[allow(trivial_numeric_casts)]
-fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: LocalDefId) {
+fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
     let def = tcx.adt_def(def_id);
-    let sp = tcx.def_span(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
 
-    if vs.is_empty() {
+    if def.variants().is_empty() {
         if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() {
             struct_span_err!(
                 tcx.sess,
@@ -1456,7 +1151,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
                 E0084,
                 "unsupported representation for zero-variant enum"
             )
-            .span_label(sp, "zero-variant enum")
+            .span_label(tcx.def_span(def_id), "zero-variant enum")
             .emit();
         }
     }
@@ -1467,88 +1162,96 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
             feature_err(
                 &tcx.sess.parse_sess,
                 sym::repr128,
-                sp,
+                tcx.def_span(def_id),
                 "repr with 128-bit type is unstable",
             )
             .emit();
         }
     }
 
-    for v in vs {
-        if let Some(ref e) = v.disr_expr {
-            tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id));
+    for v in def.variants() {
+        if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {
+            tcx.ensure().typeck(discr_def_id.expect_local());
         }
     }
 
-    if tcx.adt_def(def_id).repr().int.is_none() && tcx.features().arbitrary_enum_discriminant {
-        let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
+    if def.repr().int.is_none() {
+        let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind, CtorKind::Const);
+        let has_disr = |var: &ty::VariantDef| matches!(var.discr, ty::VariantDiscr::Explicit(_));
 
-        let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
-        let has_non_units = vs.iter().any(|var| !is_unit(var));
-        let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var));
-        let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var));
+        let has_non_units = def.variants().iter().any(|var| !is_unit(var));
+        let disr_units = def.variants().iter().any(|var| is_unit(&var) && has_disr(&var));
+        let disr_non_unit = def.variants().iter().any(|var| !is_unit(&var) && has_disr(&var));
 
         if disr_non_unit || (disr_units && has_non_units) {
-            let mut err =
-                struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified");
+            let mut err = struct_span_err!(
+                tcx.sess,
+                tcx.def_span(def_id),
+                E0732,
+                "`#[repr(inttype)]` must be specified"
+            );
             err.emit();
         }
     }
 
-    detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
-
-    check_transparent(tcx, sp, def);
+    detect_discriminant_duplicate(tcx, def);
+    check_transparent(tcx, def);
 }
 
 /// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
-fn detect_discriminant_duplicate<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    mut discrs: Vec<(VariantIdx, Discr<'tcx>)>,
-    vs: &'tcx [hir::Variant<'tcx>],
-    self_span: Span,
-) {
+fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
     // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
     // Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
-    let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| {
-        let var = &vs[idx]; // HIR for the duplicate discriminant
-        let (span, display_discr) = match var.disr_expr {
-            Some(ref expr) => {
+    let report = |dis: Discr<'tcx>, idx, err: &mut Diagnostic| {
+        let var = adt.variant(idx); // HIR for the duplicate discriminant
+        let (span, display_discr) = match var.discr {
+            ty::VariantDiscr::Explicit(discr_def_id) => {
                 // In the case the discriminant is both a duplicate and overflowed, let the user know
-                if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
+                if let hir::Node::AnonConst(expr) = tcx.hir().get_by_def_id(discr_def_id.expect_local())
+                    && let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
                     && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
                     && *lit_value != dis.val
                 {
-                    (tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
-                // Otherwise, format the value as-is
+                    (tcx.def_span(discr_def_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
                 } else {
-                    (tcx.hir().span(expr.hir_id), format!("`{dis}`"))
+                    // Otherwise, format the value as-is
+                    (tcx.def_span(discr_def_id), format!("`{dis}`"))
                 }
             }
-            None => {
+            // This should not happen.
+            ty::VariantDiscr::Relative(0) => (tcx.def_span(var.def_id), format!("`{dis}`")),
+            ty::VariantDiscr::Relative(distance_to_explicit) => {
                 // At this point we know this discriminant is a duplicate, and was not explicitly
                 // assigned by the user. Here we iterate backwards to fetch the HIR for the last
                 // explicitly assigned discriminant, and letting the user know that this was the
                 // increment startpoint, and how many steps from there leading to the duplicate
-                if let Some((n, hir::Variant { span, ident, .. })) =
-                    vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some())
+                if let Some(explicit_idx) =
+                    idx.as_u32().checked_sub(distance_to_explicit).map(VariantIdx::from_u32)
                 {
-                    let ve_ident = var.ident;
-                    let n = n + 1;
-                    let sp = if n > 1 { "variants" } else { "variant" };
+                    let explicit_variant = adt.variant(explicit_idx);
+                    let ve_ident = var.name;
+                    let ex_ident = explicit_variant.name;
+                    let sp = if distance_to_explicit > 1 { "variants" } else { "variant" };
 
                     err.span_label(
-                        *span,
-                        format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"),
+                        tcx.def_span(explicit_variant.def_id),
+                        format!(
+                            "discriminant for `{ve_ident}` incremented from this startpoint \
+                            (`{ex_ident}` + {distance_to_explicit} {sp} later \
+                             => `{ve_ident}` = {dis})"
+                        ),
                     );
                 }
 
-                (vs[idx].span, format!("`{dis}`"))
+                (tcx.def_span(var.def_id), format!("`{dis}`"))
             }
         };
 
         err.span_label(span, format!("{display_discr} assigned here"));
     };
 
+    let mut discrs = adt.discriminants(tcx).collect::<Vec<_>>();
+
     // Here we loop through the discriminants, comparing each discriminant to another.
     // When a duplicate is detected, we instantiate an error and point to both
     // initial and duplicate value. The duplicate discriminant is then discarded by swapping
@@ -1557,29 +1260,29 @@ fn detect_discriminant_duplicate<'tcx>(
     // style as we are mutating `discrs` on the fly).
     let mut i = 0;
     while i < discrs.len() {
-        let hir_var_i_idx = discrs[i].0.index();
+        let var_i_idx = discrs[i].0;
         let mut error: Option<DiagnosticBuilder<'_, _>> = None;
 
         let mut o = i + 1;
         while o < discrs.len() {
-            let hir_var_o_idx = discrs[o].0.index();
+            let var_o_idx = discrs[o].0;
 
             if discrs[i].1.val == discrs[o].1.val {
                 let err = error.get_or_insert_with(|| {
                     let mut ret = struct_span_err!(
                         tcx.sess,
-                        self_span,
+                        tcx.def_span(adt.did()),
                         E0081,
                         "discriminant value `{}` assigned more than once",
                         discrs[i].1,
                     );
 
-                    report(discrs[i].1, hir_var_i_idx, &mut ret);
+                    report(discrs[i].1, var_i_idx, &mut ret);
 
                     ret
                 });
 
-                report(discrs[o].1, hir_var_o_idx, err);
+                report(discrs[o].1, var_o_idx, err);
 
                 // Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
                 discrs[o] = *discrs.last().unwrap();
diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs
index 5e5dbedb4bd..aeaf7a6cfe1 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_method.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs
@@ -290,10 +290,7 @@ fn compare_predicate_entailment<'tcx>(
     // type would be more appropriate. In other places we have a `Vec<Span>`
     // corresponding to their `Vec<Predicate>`, but we don't have that here.
     // Fixing this would improve the output of test `issue-83765.rs`.
-    let mut result = infcx
-        .at(&cause, param_env)
-        .sup(trait_fty, impl_fty)
-        .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok));
+    let mut result = ocx.sup(&cause, param_env, trait_fty, impl_fty);
 
     // HACK(RPITIT): #101614. When we are trying to infer the hidden types for
     // RPITITs, we need to equate the output tys instead of just subtyping. If
@@ -301,12 +298,8 @@ fn compare_predicate_entailment<'tcx>(
     // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets
     // fixed up to `ReEmpty`, and which is certainly not what we want.
     if trait_fty.has_infer_types() {
-        result = result.and_then(|()| {
-            infcx
-                .at(&cause, param_env)
-                .eq(trait_sig.output(), impl_sig.output())
-                .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok))
-        });
+        result =
+            result.and_then(|()| ocx.eq(&cause, param_env, trait_sig.output(), impl_sig.output()));
     }
 
     if let Err(terr) = result {
@@ -465,30 +458,30 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
     let ocx = ObligationCtxt::new(infcx);
 
     let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
-    let impl_return_ty = ocx.normalize(
+    let impl_sig = ocx.normalize(
         norm_cause.clone(),
         param_env,
-        infcx
-            .replace_bound_vars_with_fresh_vars(
-                return_span,
-                infer::HigherRankedType,
-                tcx.fn_sig(impl_m.def_id),
-            )
-            .output(),
+        infcx.replace_bound_vars_with_fresh_vars(
+            return_span,
+            infer::HigherRankedType,
+            tcx.fn_sig(impl_m.def_id),
+        ),
     );
+    let impl_return_ty = impl_sig.output();
 
     let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
-    let unnormalized_trait_return_ty = tcx
+    let unnormalized_trait_sig = tcx
         .liberate_late_bound_regions(
             impl_m.def_id,
             tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
         )
-        .output()
         .fold_with(&mut collector);
-    let trait_return_ty =
-        ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_return_ty);
+    let trait_sig = ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_sig);
+    let trait_return_ty = trait_sig.output();
 
-    let wf_tys = FxHashSet::from_iter([unnormalized_trait_return_ty, trait_return_ty]);
+    let wf_tys = FxHashSet::from_iter(
+        unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
+    );
 
     match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) {
         Ok(infer::InferOk { value: (), obligations }) => {
@@ -521,6 +514,26 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
         }
     }
 
+    // Unify the whole function signature. We need to do this to fully infer
+    // the lifetimes of the return type, but do this after unifying just the
+    // return types, since we want to avoid duplicating errors from
+    // `compare_predicate_entailment`.
+    match infcx
+        .at(&cause, param_env)
+        .eq(tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)), tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)))
+    {
+        Ok(infer::InferOk { value: (), obligations }) => {
+            ocx.register_obligations(obligations);
+        }
+        Err(terr) => {
+            let guar = tcx.sess.delay_span_bug(
+                return_span,
+                format!("could not unify `{trait_sig}` and `{impl_sig}`: {terr:?}"),
+            );
+            return Err(guar);
+        }
+    }
+
     // Check that all obligations are satisfied by the implementation's
     // RPITs.
     let errors = ocx.select_all_or_error();
@@ -551,15 +564,48 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
                 let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
                 debug!(?id_substs, ?substs);
                 let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> =
-                    substs.iter().enumerate().map(|(index, arg)| (arg, id_substs[index])).collect();
+                    std::iter::zip(substs, id_substs).collect();
                 debug!(?map);
 
+                // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
+                // region substs that are synthesized during AST lowering. These are substs
+                // that are appended to the parent substs (trait and trait method). However,
+                // we're trying to infer the unsubstituted type value of the RPITIT inside
+                // the *impl*, so we can later use the impl's method substs to normalize
+                // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
+                //
+                // Due to the design of RPITITs, during AST lowering, we have no idea that
+                // an impl method corresponds to a trait method with RPITITs in it. Therefore,
+                // we don't have a list of early-bound region substs for the RPITIT in the impl.
+                // Since early region parameters are index-based, we can't just rebase these
+                // (trait method) early-bound region substs onto the impl, and there's no
+                // guarantee that the indices from the trait substs and impl substs line up.
+                // So to fix this, we subtract the number of trait substs and add the number of
+                // impl substs to *renumber* these early-bound regions to their corresponding
+                // indices in the impl's substitutions list.
+                //
+                // Also, we only need to account for a difference in trait and impl substs,
+                // since we previously enforce that the trait method and impl method have the
+                // same generics.
+                let num_trait_substs = trait_to_impl_substs.len();
+                let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
                 let ty = tcx.fold_regions(ty, |region, _| {
-                    if let ty::ReFree(_) = region.kind() {
-                        map[&region.into()].expect_region()
-                    } else {
-                        region
-                    }
+                    let (ty::ReFree(_) | ty::ReEarlyBound(_)) = region.kind() else { return region; };
+                    let Some(ty::ReEarlyBound(e)) = map.get(&region.into()).map(|r| r.expect_region().kind())
+                    else {
+                        tcx
+                            .sess
+                            .delay_span_bug(
+                                return_span,
+                                "expected ReFree to map to ReEarlyBound"
+                            );
+                        return tcx.lifetimes.re_static;
+                    };
+                    tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+                        def_id: e.def_id,
+                        name: e.name,
+                        index: (e.index as usize - num_trait_substs + num_impl_substs) as u32,
+                    }))
                 });
                 debug!(%ty);
                 collected_tys.insert(def_id, ty);
@@ -619,10 +665,7 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
             });
             self.types.insert(proj.item_def_id, (infer_ty, proj.substs));
             // Recurse into bounds
-            for pred in self.tcx().bound_explicit_item_bounds(proj.item_def_id).transpose_iter() {
-                let pred_span = pred.0.1;
-
-                let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx(), proj.substs);
+            for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.item_def_id).subst_iter_copied(self.tcx(), proj.substs) {
                 let pred = pred.fold_with(self);
                 let pred = self.ocx.normalize(
                     ObligationCause::misc(self.span, self.body_id),
@@ -1339,10 +1382,7 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
 
     debug!("compare_const_impl: trait_ty={:?}", trait_ty);
 
-    let err = infcx
-        .at(&cause, param_env)
-        .sup(trait_ty, impl_ty)
-        .map(|ok| ocx.register_infer_ok_obligations(ok));
+    let err = ocx.sup(&cause, param_env, trait_ty, impl_ty);
 
     if let Err(terr) = err {
         debug!(
@@ -1707,15 +1747,10 @@ pub fn check_type_bounds<'tcx>(
 
     let obligations = tcx
         .bound_explicit_item_bounds(trait_ty.def_id)
-        .transpose_iter()
-        .map(|e| e.map_bound(|e| *e).transpose_tuple2())
-        .map(|(bound, span)| {
-            debug!(?bound);
-            // this is where opaque type is found
-            let concrete_ty_bound = bound.subst(tcx, rebased_substs);
+        .subst_iter_copied(tcx, rebased_substs)
+        .map(|(concrete_ty_bound, span)| {
             debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
-
-            traits::Obligation::new(mk_cause(span.0), param_env, concrete_ty_bound)
+            traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound)
         })
         .collect();
     debug!("check_type_bounds: item_bounds={:?}", obligations);
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index e5b212eb757..a74016e220e 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -184,13 +184,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
             let p = p.kind();
             match (predicate.skip_binder(), p.skip_binder()) {
                 (ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => {
-                    // Since struct predicates cannot have ~const, project the impl predicate
-                    // onto one that ignores the constness. This is equivalent to saying that
-                    // we match a `Trait` bound on the struct with a `Trait` or `~const Trait`
-                    // in the impl.
-                    let non_const_a =
-                        ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..a };
-                    relator.relate(predicate.rebind(non_const_a), p.rebind(b)).is_ok()
+                    relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
                 }
                 (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
                     relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
@@ -198,7 +192,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
                 (
                     ty::PredicateKind::ConstEvaluatable(a),
                     ty::PredicateKind::ConstEvaluatable(b),
-                ) => tcx.try_unify_abstract_consts(self_param_env.and((a, b))),
+                ) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(),
                 (
                     ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
                     ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 8be1cf04f8b..609095c9cea 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -26,7 +26,7 @@ fn equate_intrinsic_type<'tcx>(
 ) {
     let (own_counts, span) = match &it.kind {
         hir::ForeignItemKind::Fn(.., generics) => {
-            let own_counts = tcx.generics_of(it.def_id.to_def_id()).own_counts();
+            let own_counts = tcx.generics_of(it.owner_id.to_def_id()).own_counts();
             (own_counts, generics.span)
         }
         _ => {
@@ -57,7 +57,7 @@ fn equate_intrinsic_type<'tcx>(
     {
         let fty = tcx.mk_fn_ptr(sig);
         let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType);
-        require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty);
+        require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id)), fty);
     }
 }
 
@@ -129,7 +129,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir
 /// and in `library/core/src/intrinsics.rs`.
 pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
     let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)));
-    let intrinsic_id = it.def_id.to_def_id();
+    let intrinsic_id = it.owner_id.to_def_id();
     let intrinsic_name = tcx.item_name(intrinsic_id);
     let name_str = intrinsic_name.as_str();
 
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 25228f424cd..17c4d0d482f 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -1,117 +1,11 @@
-use hir::HirId;
 use rustc_ast::InlineAsmTemplatePiece;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
-use rustc_index::vec::Idx;
-use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
 use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
 use rustc_session::lint;
 use rustc_span::{Symbol, DUMMY_SP};
-use rustc_target::abi::{Pointer, VariantIdx};
 use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType};
 
-use super::FnCtxt;
-
-/// If the type is `Option<T>`, it will return `T`, otherwise
-/// the type itself. Works on most `Option`-like types.
-fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-    let ty::Adt(def, substs) = *ty.kind() else { return ty };
-
-    if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
-        let data_idx;
-
-        let one = VariantIdx::new(1);
-        let zero = VariantIdx::new(0);
-
-        if def.variant(zero).fields.is_empty() {
-            data_idx = one;
-        } else if def.variant(one).fields.is_empty() {
-            data_idx = zero;
-        } else {
-            return ty;
-        }
-
-        if def.variant(data_idx).fields.len() == 1 {
-            return def.variant(data_idx).fields[0].ty(tcx, substs);
-        }
-    }
-
-    ty
-}
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
-        let tcx = self.tcx;
-        let span = tcx.hir().span(hir_id);
-        let normalize = |ty| {
-            let ty = self.resolve_vars_if_possible(ty);
-            self.tcx.normalize_erasing_regions(self.param_env, ty)
-        };
-        let from = normalize(from);
-        let to = normalize(to);
-        trace!(?from, ?to);
-
-        // Transmutes that are only changing lifetimes are always ok.
-        if from == to {
-            return;
-        }
-
-        let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env);
-        let sk_from = skel(from);
-        let sk_to = skel(to);
-        trace!(?sk_from, ?sk_to);
-
-        // Check for same size using the skeletons.
-        if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
-            if sk_from.same_size(sk_to) {
-                return;
-            }
-
-            // Special-case transmuting from `typeof(function)` and
-            // `Option<typeof(function)>` to present a clearer error.
-            let from = unpack_option_like(tcx, from);
-            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) {
-                struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
-                    .note(&format!("source type: {from}"))
-                    .note(&format!("target type: {to}"))
-                    .help("cast with `as` to a pointer instead")
-                    .emit();
-                return;
-            }
-        }
-
-        // Try to display a sensible error with as much information as possible.
-        let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
-            Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
-            Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
-            Err(LayoutError::Unknown(bad)) => {
-                if bad == ty {
-                    "this type does not have a fixed size".to_owned()
-                } else {
-                    format!("size can vary because of {bad}")
-                }
-            }
-            Err(err) => err.to_string(),
-        };
-
-        let mut err = struct_span_err!(
-            tcx.sess,
-            span,
-            E0512,
-            "cannot transmute between types of different sizes, \
-                                        or dependently-sized types"
-        );
-        if from == to {
-            err.note(&format!("`{from}` does not have a fixed size"));
-        } else {
-            err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
-                .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
-        }
-        err.emit();
-    }
-}
-
 pub struct InlineAsmCtxt<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -139,7 +33,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
     fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
         // Type still may have region variables, but `Sized` does not depend
         // on those, so just erase them before querying.
-        if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) {
+        if ty.is_sized(self.tcx, self.param_env) {
             return true;
         }
         if let ty::Foreign(..) = ty.kind() {
@@ -234,7 +128,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
 
         // Check that the type implements Copy. The only case where this can
         // possibly fail is for SIMD types which don't #[derive(Copy)].
-        if !ty.is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env) {
+        if !ty.is_copy_modulo_regions(self.tcx, self.param_env) {
             let msg = "arguments for inline assembly must be copyable";
             let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
             err.note(&format!("`{ty}` does not implement the Copy trait"));
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 331bd7e26c8..2e7b1025764 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -62,191 +62,45 @@ a type parameter).
 
 */
 
-pub mod _match;
-mod autoderef;
-mod callee;
-pub mod cast;
 mod check;
-mod closure;
-pub mod coercion;
 mod compare_method;
-pub mod demand;
-mod diverges;
 pub mod dropck;
-mod expectation;
-mod expr;
-mod fallback;
-mod fn_ctxt;
-mod gather_locals;
-mod generator_interior;
-mod inherited;
 pub mod intrinsic;
-mod intrinsicck;
-pub mod method;
-mod op;
-mod pat;
-mod place_op;
+pub mod intrinsicck;
 mod region;
-pub mod rvalue_scopes;
-mod upvar;
 pub mod wfcheck;
-pub mod writeback;
 
-use check::{check_abi, check_fn, check_mod_item_types};
-pub use diverges::Diverges;
-pub use expectation::Expectation;
-pub use fn_ctxt::*;
-pub use inherited::{Inherited, InheritedBuilder};
+pub use check::check_abi;
 
-use crate::astconv::AstConv;
-use crate::check::gather_locals::GatherLocalsVisitor;
+use check::check_mod_item_types;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{
-    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
-};
+use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
 use rustc_hir as hir;
-use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
 use rustc_index::bit_set::BitSet;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
-use rustc_session::config;
 use rustc_session::parse::feature_err;
-use rustc_session::Session;
 use rustc_span::source_map::DUMMY_SP;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{self, BytePos, Span, Symbol};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
-use std::cell::RefCell;
 use std::num::NonZeroU32;
 
 use crate::require_c_abi_if_c_variadic;
 use crate::util::common::indenter;
 
-use self::coercion::DynamicCoerceMany;
 use self::compare_method::collect_trait_impl_trait_tys;
 use self::region::region_scope_tree;
-pub use self::Expectation::*;
-
-#[macro_export]
-macro_rules! type_error_struct {
-    ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
-        let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
-
-        if $typ.references_error() {
-            err.downgrade_to_delayed_bug();
-        }
-
-        err
-    })
-}
-
-/// The type of a local binding, including the revealed type for anon types.
-#[derive(Copy, Clone, Debug)]
-pub struct LocalTy<'tcx> {
-    decl_ty: Ty<'tcx>,
-    revealed_ty: Ty<'tcx>,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum Needs {
-    MutPlace,
-    None,
-}
-
-impl Needs {
-    fn maybe_mut_place(m: hir::Mutability) -> Self {
-        match m {
-            hir::Mutability::Mut => Needs::MutPlace,
-            hir::Mutability::Not => Needs::None,
-        }
-    }
-}
-
-#[derive(Copy, Clone)]
-pub struct UnsafetyState {
-    pub def: hir::HirId,
-    pub unsafety: hir::Unsafety,
-    from_fn: bool,
-}
-
-impl UnsafetyState {
-    pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
-        UnsafetyState { def, unsafety, from_fn: true }
-    }
-
-    pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
-        use hir::BlockCheckMode;
-        match self.unsafety {
-            // If this unsafe, then if the outer function was already marked as
-            // unsafe we shouldn't attribute the unsafe'ness to the block. This
-            // way the block can be warned about instead of ignoring this
-            // extraneous block (functions are never warned about).
-            hir::Unsafety::Unsafe if self.from_fn => self,
-
-            unsafety => {
-                let (unsafety, def) = match blk.rules {
-                    BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
-                    BlockCheckMode::DefaultBlock => (unsafety, self.def),
-                };
-                UnsafetyState { def, unsafety, from_fn: false }
-            }
-        }
-    }
-}
-
-#[derive(Debug, Copy, Clone)]
-pub enum PlaceOp {
-    Deref,
-    Index,
-}
-
-pub struct BreakableCtxt<'tcx> {
-    may_break: bool,
-
-    // this is `null` for loops where break with a value is illegal,
-    // such as `while`, `for`, and `while let`
-    coerce: Option<DynamicCoerceMany<'tcx>>,
-}
-
-pub struct EnclosingBreakables<'tcx> {
-    stack: Vec<BreakableCtxt<'tcx>>,
-    by_id: HirIdMap<usize>,
-}
-
-impl<'tcx> EnclosingBreakables<'tcx> {
-    fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
-        self.opt_find_breakable(target_id).unwrap_or_else(|| {
-            bug!("could not find enclosing breakable with id {}", target_id);
-        })
-    }
-
-    fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
-        match self.by_id.get(&target_id) {
-            Some(ix) => Some(&mut self.stack[*ix]),
-            None => None,
-        }
-    }
-}
 
 pub fn provide(providers: &mut Providers) {
-    method::provide(providers);
     wfcheck::provide(providers);
     *providers = Providers {
-        typeck_item_bodies,
-        typeck_const_arg,
-        typeck,
-        diagnostic_only_typeck,
-        has_typeck_results,
         adt_destructor,
-        used_trait_imports,
         check_mod_item_types,
         region_scope_tree,
         collect_trait_impl_trait_tys,
@@ -259,259 +113,6 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
     tcx.calculate_dtor(def_id, dropck::check_drop_impl)
 }
 
-/// If this `DefId` is a "primary tables entry", returns
-/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
-///
-/// If this function returns `Some`, then `typeck_results(def_id)` will
-/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
-/// may not succeed. In some cases where this function returns `None`
-/// (notably closures), `typeck_results(def_id)` would wind up
-/// redirecting to the owning function.
-fn primary_body_of(
-    tcx: TyCtxt<'_>,
-    id: hir::HirId,
-) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
-    match tcx.hir().get(id) {
-        Node::Item(item) => match item.kind {
-            hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
-                Some((body, Some(ty), None))
-            }
-            hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
-            _ => None,
-        },
-        Node::TraitItem(item) => match item.kind {
-            hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
-            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
-                Some((body, None, Some(sig)))
-            }
-            _ => None,
-        },
-        Node::ImplItem(item) => match item.kind {
-            hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
-            hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
-            _ => None,
-        },
-        Node::AnonConst(constant) => Some((constant.body, None, None)),
-        _ => None,
-    }
-}
-
-fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    // Closures' typeck results come from their outermost function,
-    // as they are part of the same "inference environment".
-    let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
-    if typeck_root_def_id != def_id {
-        return tcx.has_typeck_results(typeck_root_def_id);
-    }
-
-    if let Some(def_id) = def_id.as_local() {
-        let id = tcx.hir().local_def_id_to_hir_id(def_id);
-        primary_body_of(tcx, id).is_some()
-    } else {
-        false
-    }
-}
-
-fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
-    &*tcx.typeck(def_id).used_trait_imports
-}
-
-fn typeck_const_arg<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    (did, param_did): (LocalDefId, DefId),
-) -> &ty::TypeckResults<'tcx> {
-    let fallback = move || tcx.type_of(param_did);
-    typeck_with_fallback(tcx, did, fallback)
-}
-
-fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
-    if let Some(param_did) = tcx.opt_const_param_of(def_id) {
-        tcx.typeck_const_arg((def_id, param_did))
-    } else {
-        let fallback = move || tcx.type_of(def_id.to_def_id());
-        typeck_with_fallback(tcx, def_id, fallback)
-    }
-}
-
-/// Used only to get `TypeckResults` for type inference during error recovery.
-/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
-fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
-    let fallback = move || {
-        let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
-        tcx.ty_error_with_message(span, "diagnostic only typeck table used")
-    };
-    typeck_with_fallback(tcx, def_id, fallback)
-}
-
-fn typeck_with_fallback<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-    fallback: impl Fn() -> Ty<'tcx> + 'tcx,
-) -> &'tcx ty::TypeckResults<'tcx> {
-    // Closures' typeck results come from their outermost function,
-    // as they are part of the same "inference environment".
-    let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
-    if typeck_root_def_id != def_id {
-        return tcx.typeck(typeck_root_def_id);
-    }
-
-    let id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let span = tcx.hir().span(id);
-
-    // Figure out what primary body this item has.
-    let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
-        span_bug!(span, "can't type-check body of {:?}", def_id);
-    });
-    let body = tcx.hir().body(body_id);
-
-    let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
-        let param_env = tcx.param_env(def_id);
-        let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
-            let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
-                let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
-                <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
-            } else {
-                tcx.fn_sig(def_id)
-            };
-
-            check_abi(tcx, id, span, fn_sig.abi());
-
-            // Compute the function signature from point of view of inside the fn.
-            let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
-            let fn_sig = inh.normalize_associated_types_in(
-                body.value.span,
-                body_id.hir_id,
-                param_env,
-                fn_sig,
-            );
-            check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
-        } else {
-            let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
-            let expected_type = body_ty
-                .and_then(|ty| match ty.kind {
-                    hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
-                    _ => None,
-                })
-                .unwrap_or_else(|| match tcx.hir().get(id) {
-                    Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
-                        Node::Expr(&hir::Expr {
-                            kind: hir::ExprKind::ConstBlock(ref anon_const),
-                            ..
-                        }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
-                            kind: TypeVariableOriginKind::TypeInference,
-                            span,
-                        }),
-                        Node::Ty(&hir::Ty {
-                            kind: hir::TyKind::Typeof(ref anon_const), ..
-                        }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
-                            kind: TypeVariableOriginKind::TypeInference,
-                            span,
-                        }),
-                        Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
-                        | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
-                            let operand_ty = asm
-                                .operands
-                                .iter()
-                                .filter_map(|(op, _op_sp)| match op {
-                                    hir::InlineAsmOperand::Const { anon_const }
-                                        if anon_const.hir_id == id =>
-                                    {
-                                        // Inline assembly constants must be integers.
-                                        Some(fcx.next_int_var())
-                                    }
-                                    hir::InlineAsmOperand::SymFn { anon_const }
-                                        if anon_const.hir_id == id =>
-                                    {
-                                        Some(fcx.next_ty_var(TypeVariableOrigin {
-                                            kind: TypeVariableOriginKind::MiscVariable,
-                                            span,
-                                        }))
-                                    }
-                                    _ => None,
-                                })
-                                .next();
-                            operand_ty.unwrap_or_else(fallback)
-                        }
-                        _ => fallback(),
-                    },
-                    _ => fallback(),
-                });
-
-            let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
-            fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
-
-            // Gather locals in statics (because of block expressions).
-            GatherLocalsVisitor::new(&fcx).visit_body(body);
-
-            fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
-
-            fcx.write_ty(id, expected_type);
-
-            fcx
-        };
-
-        let fallback_has_occurred = fcx.type_inference_fallback();
-
-        // Even though coercion casts provide type hints, we check casts after fallback for
-        // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
-        fcx.check_casts();
-        fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
-
-        // Closure and generator analysis may run after fallback
-        // because they don't constrain other type variables.
-        // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
-        let prev_constness = fcx.param_env.constness();
-        fcx.param_env = fcx.param_env.without_const();
-        fcx.closure_analyze(body);
-        fcx.param_env = fcx.param_env.with_constness(prev_constness);
-        assert!(fcx.deferred_call_resolutions.borrow().is_empty());
-        // Before the generator analysis, temporary scopes shall be marked to provide more
-        // precise information on types to be captured.
-        fcx.resolve_rvalue_scopes(def_id.to_def_id());
-        fcx.resolve_generator_interiors(def_id.to_def_id());
-
-        for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
-            let ty = fcx.normalize_ty(span, ty);
-            fcx.require_type_is_sized(ty, span, code);
-        }
-
-        fcx.select_all_obligations_or_error();
-
-        if !fcx.infcx.is_tainted_by_errors() {
-            fcx.check_transmutes();
-        }
-
-        fcx.check_asms();
-
-        fcx.infcx.skip_region_resolution();
-
-        fcx.resolve_type_vars_in_body(body)
-    });
-
-    // Consistency check our TypeckResults instance can hold all ItemLocalIds
-    // it will need to hold.
-    assert_eq!(typeck_results.hir_owner, id.owner);
-
-    typeck_results
-}
-
-/// When `check_fn` is invoked on a generator (i.e., a body that
-/// includes yield), it returns back some information about the yield
-/// points.
-struct GeneratorTypes<'tcx> {
-    /// Type of generator argument / values returned by `yield`.
-    resume_ty: Ty<'tcx>,
-
-    /// Type of value that is yielded.
-    yield_ty: Ty<'tcx>,
-
-    /// Types that are captured (see `GeneratorInterior` for more).
-    interior: Ty<'tcx>,
-
-    /// Indicates if the generator is movable or static (immovable).
-    movability: hir::Movability,
-}
-
 /// Given a `DefId` for an opaque type in return position, find its parent item's return
 /// expressions.
 fn get_owner_return_paths<'tcx>(
@@ -528,9 +129,10 @@ fn get_owner_return_paths<'tcx>(
     })
 }
 
-// Forbid defining intrinsics in Rust code,
-// as they must always be defined by the compiler.
-fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
+/// Forbid defining intrinsics in Rust code,
+/// as they must always be defined by the compiler.
+// FIXME: Move this to a more appropriate place.
+pub fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
     if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
         tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
     }
@@ -824,6 +426,17 @@ fn fn_sig_suggestion<'tcx>(
     format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
 }
 
+pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
+    Some(match ty.kind() {
+        ty::Bool => "true",
+        ty::Char => "'a'",
+        ty::Int(_) | ty::Uint(_) => "42",
+        ty::Float(_) => "3.14159",
+        ty::Error(_) | ty::Never => return None,
+        _ => "value",
+    })
+}
+
 /// Return placeholder code for the given associated item.
 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
 /// structured suggestion.
@@ -845,7 +458,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
         ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
         ty::AssocKind::Const => {
             let ty = tcx.type_of(assoc.def_id);
-            let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
+            let val = ty_kind_suggestion(ty).unwrap_or("value");
             format!("const {}: {} = {};", assoc.name, ty, val)
         }
     }
@@ -896,76 +509,7 @@ fn bad_non_zero_sized_fields<'tcx>(
     err.emit();
 }
 
-fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
-    struct_span_err!(
-        tcx.sess,
-        span,
-        E0533,
-        "expected unit struct, unit variant or constant, found {} `{}`",
-        res.descr(),
-        rustc_hir_pretty::qpath_to_string(qpath),
-    )
-    .emit();
-}
-
-/// Controls whether the arguments are tupled. This is used for the call
-/// operator.
-///
-/// Tupling means that all call-side arguments are packed into a tuple and
-/// passed as a single parameter. For example, if tupling is enabled, this
-/// function:
-/// ```
-/// fn f(x: (isize, isize)) {}
-/// ```
-/// Can be called as:
-/// ```ignore UNSOLVED (can this be done in user code?)
-/// # fn f(x: (isize, isize)) {}
-/// f(1, 2);
-/// ```
-/// Instead of:
-/// ```
-/// # fn f(x: (isize, isize)) {}
-/// f((1, 2));
-/// ```
-#[derive(Clone, Eq, PartialEq)]
-enum TupleArgumentsFlag {
-    DontTupleArguments,
-    TupleArguments,
-}
-
-fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
-    tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
-}
-
-fn fatally_break_rust(sess: &Session) {
-    let handler = sess.diagnostic();
-    handler.span_bug_no_panic(
-        MultiSpan::new(),
-        "It looks like you're trying to break rust; would you like some ICE?",
-    );
-    handler.note_without_error("the compiler expectedly panicked. this is a feature.");
-    handler.note_without_error(
-        "we would appreciate a joke overview: \
-         https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
-    );
-    handler.note_without_error(&format!(
-        "rustc {} running on {}",
-        option_env!("CFG_VERSION").unwrap_or("unknown_version"),
-        config::host_triple(),
-    ));
-}
-
-fn potentially_plural_count(count: usize, word: &str) -> String {
+// FIXME: Consider moving this method to a more fitting place.
+pub fn potentially_plural_count(count: usize, word: &str) -> String {
     format!("{} {}{}", count, word, pluralize!(count))
 }
-
-fn has_expected_num_generic_args<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_did: Option<DefId>,
-    expected: usize,
-) -> bool {
-    trait_did.map_or(true, |trait_did| {
-        let generics = tcx.generics_of(trait_did);
-        generics.count() == expected + if generics.has_self { 1 } else { 0 }
-    })
-}
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index b89db79bef8..ff32329e431 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -252,9 +252,13 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
             ) => {
                 // For shortcircuiting operators, mark the RHS as a terminating
                 // scope since it only executes conditionally.
-                terminating(r.hir_id.local_id);
-            }
 
+                // `Let` expressions (in a let-chain) shouldn't be terminating, as their temporaries
+                // should live beyond the immediate expression
+                if !matches!(r.kind, hir::ExprKind::Let(_)) {
+                    terminating(r.hir_id.local_id);
+                }
+            }
             hir::ExprKind::If(_, ref then, Some(ref otherwise)) => {
                 terminating(then.hir_id.local_id);
                 terminating(otherwise.hir_id.local_id);
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 0a8a1bec9b8..0117bdd0ba8 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -147,10 +147,10 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
 /// the types first.
 #[instrument(skip(tcx), level = "debug")]
 fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
-    let def_id = item.def_id.def_id;
+    let def_id = item.owner_id.def_id;
 
     debug!(
-        ?item.def_id,
+        ?item.owner_id,
         item.name = ? tcx.def_path_str(def_id.to_def_id())
     );
 
@@ -218,19 +218,16 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
         hir::ItemKind::Const(ty, ..) => {
             check_item_type(tcx, def_id, ty.span, false);
         }
-        hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
-            check_type_defn(tcx, item, false, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
-
+        hir::ItemKind::Struct(_, ref ast_generics) => {
+            check_type_defn(tcx, item, false);
             check_variances_for_type_defn(tcx, item, ast_generics);
         }
-        hir::ItemKind::Union(ref struct_def, ref ast_generics) => {
-            check_type_defn(tcx, item, true, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
-
+        hir::ItemKind::Union(_, ref ast_generics) => {
+            check_type_defn(tcx, item, true);
             check_variances_for_type_defn(tcx, item, ast_generics);
         }
-        hir::ItemKind::Enum(ref enum_def, ref ast_generics) => {
-            check_type_defn(tcx, item, true, |wfcx| wfcx.enum_variants(enum_def));
-
+        hir::ItemKind::Enum(_, ref ast_generics) => {
+            check_type_defn(tcx, item, true);
             check_variances_for_type_defn(tcx, item, ast_generics);
         }
         hir::ItemKind::Trait(..) => {
@@ -246,10 +243,10 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
 }
 
 fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
-    let def_id = item.def_id.def_id;
+    let def_id = item.owner_id.def_id;
 
     debug!(
-        ?item.def_id,
+        ?item.owner_id,
         item.name = ? tcx.def_path_str(def_id.to_def_id())
     );
 
@@ -263,7 +260,7 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
 }
 
 fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
-    let def_id = trait_item.def_id.def_id;
+    let def_id = trait_item.owner_id.def_id;
 
     let (method_sig, span) = match trait_item.kind {
         hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span),
@@ -275,7 +272,7 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
 
     let encl_trait_def_id = tcx.local_parent(def_id);
     let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
-    let encl_trait_def_id = encl_trait.def_id.to_def_id();
+    let encl_trait_def_id = encl_trait.owner_id.to_def_id();
     let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
         Some("fn")
     } else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() {
@@ -348,7 +345,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
     loop {
         let mut should_continue = false;
         for gat_item in associated_items {
-            let gat_def_id = gat_item.id.def_id;
+            let gat_def_id = gat_item.id.owner_id;
             let gat_item = tcx.associated_item(gat_def_id);
             // If this item is not an assoc ty, or has no substs, then it's not a GAT
             if gat_item.kind != ty::AssocKind::Type {
@@ -365,7 +362,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
             // constrains the GAT with individually.
             let mut new_required_bounds: Option<FxHashSet<ty::Predicate<'_>>> = None;
             for item in associated_items {
-                let item_def_id = item.id.def_id;
+                let item_def_id = item.id.owner_id;
                 // Skip our own GAT, since it does not constrain itself at all.
                 if item_def_id == gat_def_id {
                     continue;
@@ -713,6 +710,10 @@ fn resolve_regions_with_wf_tys<'tcx>(
 
     add_constraints(&infcx, region_bound_pairs);
 
+    infcx.process_registered_region_obligations(
+        outlives_environment.region_bound_pairs(),
+        param_env,
+    );
     let errors = infcx.resolve_regions(&outlives_environment);
 
     debug!(?errors, "errors");
@@ -786,7 +787,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
     let (trait_name, trait_def_id) =
         match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(item.hir_id()).def_id) {
             hir::Node::Item(item) => match item.kind {
-                hir::ItemKind::Trait(..) => (item.ident, item.def_id),
+                hir::ItemKind::Trait(..) => (item.ident, item.owner_id),
                 _ => return,
             },
             _ => return,
@@ -841,7 +842,7 @@ fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) {
         _ => (None, impl_item.span),
     };
 
-    check_associated_item(tcx, impl_item.def_id.def_id, span, method_sig);
+    check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig);
 }
 
 fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
@@ -1033,27 +1034,25 @@ fn item_adt_kind(kind: &ItemKind<'_>) -> Option<AdtKind> {
 }
 
 /// In a type definition, we check that to ensure that the types of the fields are well-formed.
-fn check_type_defn<'tcx, F>(
-    tcx: TyCtxt<'tcx>,
-    item: &hir::Item<'tcx>,
-    all_sized: bool,
-    mut lookup_fields: F,
-) where
-    F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
-{
-    let _ = tcx.representability(item.def_id.def_id);
+fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: bool) {
+    let _ = tcx.representability(item.owner_id.def_id);
+    let adt_def = tcx.adt_def(item.owner_id);
 
-    enter_wf_checking_ctxt(tcx, item.span, item.def_id.def_id, |wfcx| {
-        let variants = lookup_fields(wfcx);
-        let packed = tcx.adt_def(item.def_id).repr().packed();
+    enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
+        let variants = adt_def.variants();
+        let packed = adt_def.repr().packed();
 
-        for variant in &variants {
+        for variant in variants.iter() {
             // All field types must be well-formed.
             for field in &variant.fields {
+                let field_id = field.did.expect_local();
+                let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
+                else { bug!() };
+                let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
                 wfcx.register_wf_obligation(
-                    field.span,
-                    Some(WellFormedLoc::Ty(field.def_id)),
-                    field.ty.into(),
+                    hir_ty.span,
+                    Some(WellFormedLoc::Ty(field_id)),
+                    ty.into(),
                 )
             }
 
@@ -1061,7 +1060,7 @@ fn check_type_defn<'tcx, F>(
             // intermediate types must be sized.
             let needs_drop_copy = || {
                 packed && {
-                    let ty = variant.fields.last().unwrap().ty;
+                    let ty = tcx.type_of(variant.fields.last().unwrap().did);
                     let ty = tcx.erase_regions(ty);
                     if ty.needs_infer() {
                         tcx.sess
@@ -1069,7 +1068,7 @@ fn check_type_defn<'tcx, F>(
                         // Just treat unresolved type expression as if it needs drop.
                         true
                     } else {
-                        ty.needs_drop(tcx, tcx.param_env(item.def_id))
+                        ty.needs_drop(tcx, tcx.param_env(item.owner_id))
                     }
                 }
             };
@@ -1080,29 +1079,31 @@ fn check_type_defn<'tcx, F>(
                 variant.fields[..variant.fields.len() - unsized_len].iter().enumerate()
             {
                 let last = idx == variant.fields.len() - 1;
+                let field_id = field.did.expect_local();
+                let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
+                else { bug!() };
+                let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
                 wfcx.register_bound(
                     traits::ObligationCause::new(
-                        field.span,
+                        hir_ty.span,
                         wfcx.body_id,
                         traits::FieldSized {
                             adt_kind: match item_adt_kind(&item.kind) {
                                 Some(i) => i,
                                 None => bug!(),
                             },
-                            span: field.span,
+                            span: hir_ty.span,
                             last,
                         },
                     ),
                     wfcx.param_env,
-                    field.ty,
+                    ty,
                     tcx.require_lang_item(LangItem::Sized, None),
                 );
             }
 
             // Explicit `enum` discriminant values must const-evaluate successfully.
-            if let Some(discr_def_id) = variant.explicit_discr {
-                let discr_substs = InternalSubsts::identity_for_item(tcx, discr_def_id.to_def_id());
-
+            if let ty::VariantDiscr::Explicit(discr_def_id) = variant.discr {
                 let cause = traits::ObligationCause::new(
                     tcx.def_span(discr_def_id),
                     wfcx.body_id,
@@ -1112,25 +1113,22 @@ fn check_type_defn<'tcx, F>(
                     cause,
                     wfcx.param_env,
                     ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
-                        ty::UnevaluatedConst::new(
-                            ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
-                            discr_substs,
-                        ),
+                        ty::Const::from_anon_const(tcx, discr_def_id.expect_local()),
                     ))
                     .to_predicate(tcx),
                 ));
             }
         }
 
-        check_where_clauses(wfcx, item.span, item.def_id.def_id);
+        check_where_clauses(wfcx, item.span, item.owner_id.def_id);
     });
 }
 
 #[instrument(skip(tcx, item))]
 fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
-    debug!(?item.def_id);
+    debug!(?item.owner_id);
 
-    let def_id = item.def_id.def_id;
+    let def_id = item.owner_id.def_id;
     let trait_def = tcx.trait_def(def_id);
     if trait_def.is_marker
         || matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker)
@@ -1241,13 +1239,13 @@ fn check_impl<'tcx>(
     ast_trait_ref: &Option<hir::TraitRef<'_>>,
     constness: hir::Constness,
 ) {
-    enter_wf_checking_ctxt(tcx, item.span, item.def_id.def_id, |wfcx| {
+    enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
         match *ast_trait_ref {
             Some(ref ast_trait_ref) => {
                 // `#[rustc_reservation_impl]` impls are not real impls and
                 // therefore don't need to be WF (the trait's `Self: Trait` predicate
                 // won't hold).
-                let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap();
+                let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap();
                 let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref);
                 let trait_pred = ty::TraitPredicate {
                     trait_ref,
@@ -1269,7 +1267,7 @@ fn check_impl<'tcx>(
                 wfcx.register_obligations(obligations);
             }
             None => {
-                let self_ty = tcx.type_of(item.def_id);
+                let self_ty = tcx.type_of(item.owner_id);
                 let self_ty = wfcx.normalize(
                     item.span,
                     Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
@@ -1283,7 +1281,7 @@ fn check_impl<'tcx>(
             }
         }
 
-        check_where_clauses(wfcx, item.span, item.def_id.def_id);
+        check_where_clauses(wfcx, item.span, item.owner_id.def_id);
     });
 }
 
@@ -1676,7 +1674,7 @@ fn receiver_is_valid<'tcx>(
 
     // `self: Self` is always valid.
     if can_eq_self(receiver_ty) {
-        if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, receiver_ty) {
+        if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, receiver_ty) {
             infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
         }
         return true;
@@ -1706,9 +1704,7 @@ fn receiver_is_valid<'tcx>(
             if can_eq_self(potential_self_ty) {
                 wfcx.register_obligations(autoderef.into_obligations());
 
-                if let Err(err) =
-                    wfcx.equate_types(&cause, wfcx.param_env, self_ty, potential_self_ty)
-                {
+                if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty) {
                     infcx
                         .err_ctxt()
                         .report_mismatched_types(&cause, self_ty, potential_self_ty, err)
@@ -1779,14 +1775,14 @@ fn check_variances_for_type_defn<'tcx>(
     item: &hir::Item<'tcx>,
     hir_generics: &hir::Generics<'_>,
 ) {
-    let ty = tcx.type_of(item.def_id);
+    let ty = tcx.type_of(item.owner_id);
     if tcx.has_error_field(ty) {
         return;
     }
 
-    let ty_predicates = tcx.predicates_of(item.def_id);
+    let ty_predicates = tcx.predicates_of(item.owner_id);
     assert_eq!(ty_predicates.parent, None);
-    let variances = tcx.variances_of(item.def_id);
+    let variances = tcx.variances_of(item.owner_id);
 
     let mut constrained_parameters: FxHashSet<_> = variances
         .iter()
@@ -1799,7 +1795,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.def_id.to_def_id());
+        let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.to_def_id());
         hir_generics
             .predicates
             .iter()
@@ -1920,60 +1916,10 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
 
 fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) {
     let items = tcx.hir_module_items(module);
-    items.par_items(|item| tcx.ensure().check_well_formed(item.def_id));
-    items.par_impl_items(|item| tcx.ensure().check_well_formed(item.def_id));
-    items.par_trait_items(|item| tcx.ensure().check_well_formed(item.def_id));
-    items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.def_id));
-}
-
-///////////////////////////////////////////////////////////////////////////
-// ADT
-
-// FIXME(eddyb) replace this with getting fields/discriminants through `ty::AdtDef`.
-struct AdtVariant<'tcx> {
-    /// Types of fields in the variant, that must be well-formed.
-    fields: Vec<AdtField<'tcx>>,
-
-    /// Explicit discriminant of this variant (e.g. `A = 123`),
-    /// that must evaluate to a constant value.
-    explicit_discr: Option<LocalDefId>,
-}
-
-struct AdtField<'tcx> {
-    ty: Ty<'tcx>,
-    def_id: LocalDefId,
-    span: Span,
-}
-
-impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> {
-    // FIXME(eddyb) replace this with getting fields through `ty::AdtDef`.
-    fn non_enum_variant(&self, struct_def: &hir::VariantData<'_>) -> AdtVariant<'tcx> {
-        let fields = struct_def
-            .fields()
-            .iter()
-            .map(|field| {
-                let def_id = self.tcx().hir().local_def_id(field.hir_id);
-                let field_ty = self.tcx().type_of(def_id);
-                let field_ty = self.normalize(field.ty.span, None, field_ty);
-                debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty);
-                AdtField { ty: field_ty, span: field.ty.span, def_id }
-            })
-            .collect();
-        AdtVariant { fields, explicit_discr: None }
-    }
-
-    fn enum_variants(&self, enum_def: &hir::EnumDef<'_>) -> Vec<AdtVariant<'tcx>> {
-        enum_def
-            .variants
-            .iter()
-            .map(|variant| AdtVariant {
-                fields: self.non_enum_variant(&variant.data).fields,
-                explicit_discr: variant
-                    .disr_expr
-                    .map(|explicit_discr| self.tcx().hir().local_def_id(explicit_discr.hir_id)),
-            })
-            .collect()
-    }
+    items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+    items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+    items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+    items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id));
 }
 
 fn error_392(
diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index 922833f8580..d0c31733481 100644
--- a/compiler/rustc_hir_analysis/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
@@ -1,5 +1,6 @@
 use crate::errors::{ExternCrateNotIdiomatic, UnusedExternCrate};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unord::UnordSet;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -8,12 +9,12 @@ use rustc_session::lint;
 use rustc_span::{Span, Symbol};
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
-    let mut used_trait_imports: FxHashSet<LocalDefId> = FxHashSet::default();
+    let mut used_trait_imports: UnordSet<LocalDefId> = Default::default();
 
     for item_def_id in tcx.hir().body_owners() {
         let imports = tcx.used_trait_imports(item_def_id);
         debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
-        used_trait_imports.extend(imports.iter());
+        used_trait_imports.extend(imports.items().copied());
     }
 
     for &id in tcx.maybe_unused_trait_imports(()) {
@@ -89,11 +90,11 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
     let mut crates_to_lint = vec![];
 
     for id in tcx.hir().items() {
-        if matches!(tcx.def_kind(id.def_id), DefKind::ExternCrate) {
+        if matches!(tcx.def_kind(id.owner_id), DefKind::ExternCrate) {
             let item = tcx.hir().item(id);
             if let hir::ItemKind::ExternCrate(orig_name) = item.kind {
                 crates_to_lint.push(ExternCrateToLint {
-                    def_id: item.def_id.to_def_id(),
+                    def_id: item.owner_id.to_def_id(),
                     span: item.span,
                     orig_name,
                     warn_if_unused: !item.ident.as_str().starts_with('_'),
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 308ad5d5fc2..2890c149b3a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -58,7 +58,7 @@ const ADD_ATTR: &str =
 
 impl<'tcx> InherentCollect<'tcx> {
     fn check_def_id(&mut self, item: &hir::Item<'_>, self_ty: Ty<'tcx>, def_id: DefId) {
-        let impl_def_id = item.def_id;
+        let impl_def_id = item.owner_id;
         if let Some(def_id) = def_id.as_local() {
             // Add the implementation to the mapping from implementation to base
             // type def ID, if there is a base type for this implementation and
@@ -89,7 +89,7 @@ impl<'tcx> InherentCollect<'tcx> {
             for impl_item in items {
                 if !self
                     .tcx
-                    .has_attr(impl_item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+                    .has_attr(impl_item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl)
                 {
                     struct_span_err!(
                         self.tcx.sess,
@@ -135,7 +135,7 @@ impl<'tcx> InherentCollect<'tcx> {
                 for item in items {
                     if !self
                         .tcx
-                        .has_attr(item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+                        .has_attr(item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl)
                     {
                         struct_span_err!(
                             self.tcx.sess,
@@ -177,7 +177,7 @@ impl<'tcx> InherentCollect<'tcx> {
     }
 
     fn check_item(&mut self, id: hir::ItemId) {
-        if !matches!(self.tcx.def_kind(id.def_id), DefKind::Impl) {
+        if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl) {
             return;
         }
 
@@ -186,7 +186,7 @@ impl<'tcx> InherentCollect<'tcx> {
             return;
         };
 
-        let self_ty = self.tcx.type_of(item.def_id);
+        let self_ty = self.tcx.type_of(item.owner_id);
         match *self_ty.kind() {
             ty::Adt(def, _) => {
                 self.check_def_id(item, self_ty, def.did());
@@ -221,7 +221,7 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::Never
             | ty::FnPtr(_)
             | ty::Tuple(..) => {
-                self.check_primitive_impl(item.def_id.def_id, self_ty, items, ty.span)
+                self.check_primitive_impl(item.owner_id.def_id, self_ty, items, ty.span)
             }
             ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
                 let mut err = struct_span_err!(
@@ -243,7 +243,7 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::Bound(..)
             | ty::Placeholder(_)
             | ty::Infer(_) => {
-                bug!("unexpected impl self type of impl: {:?} {:?}", item.def_id, self_ty);
+                bug!("unexpected impl self type of impl: {:?} {:?}", item.owner_id, self_ty);
             }
             ty::Error(_) => {}
         }
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index 03e076bf5ec..972769eb197 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -58,6 +58,37 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
                 == item2.ident(self.tcx).normalize_to_macros_2_0()
     }
 
+    fn check_for_duplicate_items_in_impl(&self, impl_: DefId) {
+        let impl_items = self.tcx.associated_items(impl_);
+
+        let mut seen_items = FxHashMap::default();
+        for impl_item in impl_items.in_definition_order() {
+            let span = self.tcx.def_span(impl_item.def_id);
+            let ident = impl_item.ident(self.tcx);
+
+            let norm_ident = ident.normalize_to_macros_2_0();
+            match seen_items.entry(norm_ident) {
+                Entry::Occupied(entry) => {
+                    let former = entry.get();
+                    let mut err = struct_span_err!(
+                        self.tcx.sess,
+                        span,
+                        E0592,
+                        "duplicate definitions with name `{}`",
+                        ident,
+                    );
+                    err.span_label(span, format!("duplicate definitions for `{}`", ident));
+                    err.span_label(*former, format!("other definition for `{}`", ident));
+
+                    err.emit();
+                }
+                Entry::Vacant(entry) => {
+                    entry.insert(span);
+                }
+            }
+        }
+    }
+
     fn check_for_common_items_in_impls(
         &self,
         impl1: DefId,
@@ -117,29 +148,22 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
             // inherent impls without warning.
             SkipLeakCheck::Yes,
             overlap_mode,
-            |overlap| {
-                self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
-                false
-            },
-            || true,
-        );
+        )
+        .map_or(true, |overlap| {
+            self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
+            false
+        });
     }
 
     fn check_item(&mut self, id: hir::ItemId) {
-        let def_kind = self.tcx.def_kind(id.def_id);
+        let def_kind = self.tcx.def_kind(id.owner_id);
         if !matches!(def_kind, DefKind::Enum | DefKind::Struct | DefKind::Trait | DefKind::Union) {
             return;
         }
 
-        let impls = self.tcx.inherent_impls(id.def_id);
+        let impls = self.tcx.inherent_impls(id.owner_id);
 
-        // If there is only one inherent impl block,
-        // there is nothing to overlap check it with
-        if impls.len() <= 1 {
-            return;
-        }
-
-        let overlap_mode = OverlapMode::get(self.tcx, id.def_id.to_def_id());
+        let overlap_mode = OverlapMode::get(self.tcx, id.owner_id.to_def_id());
 
         let impls_items = impls
             .iter()
@@ -152,6 +176,8 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
         const ALLOCATING_ALGO_THRESHOLD: usize = 500;
         if impls.len() < ALLOCATING_ALGO_THRESHOLD {
             for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() {
+                self.check_for_duplicate_items_in_impl(impl1_def_id);
+
                 for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] {
                     if self.impls_have_common_items(impl_items1, impl_items2) {
                         self.check_for_overlapping_inherent_impls(
@@ -290,6 +316,8 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
                 impl_blocks.sort_unstable();
                 for (i, &impl1_items_idx) in impl_blocks.iter().enumerate() {
                     let &(&impl1_def_id, impl_items1) = &impls_items[impl1_items_idx];
+                    self.check_for_duplicate_items_in_impl(impl1_def_id);
+
                     for &impl2_items_idx in impl_blocks[(i + 1)..].iter() {
                         let &(&impl2_def_id, impl_items2) = &impls_items[impl2_items_idx];
                         if self.impls_have_common_items(impl_items1, impl_items2) {
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 1307f74f210..71c932d747b 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -23,9 +23,7 @@ pub(crate) fn orphan_check_impl(
     impl_def_id: LocalDefId,
 ) -> Result<(), ErrorGuaranteed> {
     let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
-    if let Some(err) = trait_ref.error_reported() {
-        return Err(err);
-    }
+    trait_ref.error_reported()?;
 
     let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id);
     if tcx.trait_is_auto(trait_ref.def_id) {
@@ -101,7 +99,7 @@ fn do_orphan_check_impl<'tcx>(
         span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
     }
 
-    match traits::orphan_check(tcx, item.def_id.to_def_id()) {
+    match traits::orphan_check(tcx, item.owner_id.to_def_id()) {
         Ok(()) => {}
         Err(err) => emit_orphan_check_error(
             tcx,
diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index e45fb5fe41c..a34815b45b3 100644
--- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -13,7 +13,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let item = tcx.hir().expect_item(def_id);
     let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
 
-    if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
+    if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
         let trait_def = tcx.trait_def(trait_ref.def_id);
         let unsafe_attr =
             impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
@@ -26,6 +26,12 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                     "implementing the trait `{}` is not unsafe",
                     trait_ref.print_only_trait_path()
                 )
+                .span_suggestion_verbose(
+                    item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
+                    "remove `unsafe` from this trait implementation",
+                    "",
+                    rustc_errors::Applicability::MachineApplicable,
+                )
                 .emit();
             }
 
@@ -37,6 +43,18 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                     "the trait `{}` requires an `unsafe impl` declaration",
                     trait_ref.print_only_trait_path()
                 )
+                .note(format!(
+                    "the trait `{}` enforces invariants that the compiler can't check. \
+                    Review the trait documentation and make sure this implementation \
+                    upholds those invariants before adding the `unsafe` keyword",
+                    trait_ref.print_only_trait_path()
+                ))
+                .span_suggestion_verbose(
+                    item.span.shrink_to_lo(),
+                    "add `unsafe` to this trait implementation",
+                    "unsafe ",
+                    rustc_errors::Applicability::MaybeIncorrect,
+                )
                 .emit();
             }
 
@@ -48,6 +66,18 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                     "requires an `unsafe impl` declaration due to `#[{}]` attribute",
                     attr_name
                 )
+                .note(format!(
+                    "the trait `{}` enforces invariants that the compiler can't check. \
+                    Review the trait documentation and make sure this implementation \
+                    upholds those invariants before adding the `unsafe` keyword",
+                    trait_ref.print_only_trait_path()
+                ))
+                .span_suggestion_verbose(
+                    item.span.shrink_to_lo(),
+                    "add `unsafe` to this trait implementation",
+                    "unsafe ",
+                    rustc_errors::Applicability::MaybeIncorrect,
+                )
                 .emit();
             }
 
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 5c76016c662..25faacadf3d 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -27,8 +27,8 @@ use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::weak_lang_items;
-use rustc_hir::{GenericParamKind, Node};
+use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
+use rustc_hir::{lang_items, GenericParamKind, LangItem, Node};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::mono::Linkage;
@@ -100,13 +100,12 @@ pub fn provide(providers: &mut Providers) {
 /// It's also used for the bodies of items like structs where the body (the fields)
 /// are just signatures.
 ///
-/// This is in contrast to [`FnCtxt`], which is used to type-check bodies of
+/// This is in contrast to `FnCtxt`, which is used to type-check bodies of
 /// functions, closures, and `const`s -- anywhere that expressions and statements show up.
 ///
 /// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] --
 /// while `FnCtxt` does do inference.
 ///
-/// [`FnCtxt`]: crate::check::FnCtxt
 /// [`InferCtxt`]: rustc_infer::infer::InferCtxt
 ///
 /// # Trait predicates
@@ -380,8 +379,8 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
         self.tcx
     }
 
-    fn item_def_id(&self) -> Option<DefId> {
-        Some(self.item_def_id)
+    fn item_def_id(&self) -> DefId {
+        self.item_def_id
     }
 
     fn get_type_parameter_bounds(
@@ -572,7 +571,7 @@ fn get_new_lifetime_name<'tcx>(
 fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
     let it = tcx.hir().item(item_id);
     debug!("convert: item {} with id {}", it.ident, it.hir_id());
-    let def_id = item_id.def_id.def_id;
+    let def_id = item_id.owner_id.def_id;
 
     match it.kind {
         // These don't define types.
@@ -584,11 +583,11 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
         hir::ItemKind::ForeignMod { items, .. } => {
             for item in items {
                 let item = tcx.hir().foreign_item(item.id);
-                tcx.ensure().generics_of(item.def_id);
-                tcx.ensure().type_of(item.def_id);
-                tcx.ensure().predicates_of(item.def_id);
+                tcx.ensure().generics_of(item.owner_id);
+                tcx.ensure().type_of(item.owner_id);
+                tcx.ensure().predicates_of(item.owner_id);
                 match item.kind {
-                    hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.def_id),
+                    hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.owner_id),
                     hir::ForeignItemKind::Static(..) => {
                         let mut visitor = HirPlaceholderCollector::default();
                         visitor.visit_foreign_item(item);
@@ -605,11 +604,11 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                 }
             }
         }
-        hir::ItemKind::Enum(ref enum_definition, _) => {
+        hir::ItemKind::Enum(..) => {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().type_of(def_id);
             tcx.ensure().predicates_of(def_id);
-            convert_enum_variant_types(tcx, def_id.to_def_id(), enum_definition.variants);
+            convert_enum_variant_types(tcx, def_id.to_def_id());
         }
         hir::ItemKind::Impl { .. } => {
             tcx.ensure().generics_of(def_id);
@@ -641,7 +640,8 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             }
 
             if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
-                convert_variant_ctor(tcx, ctor_hir_id);
+                let ctor_def_id = tcx.hir().local_def_id(ctor_hir_id);
+                convert_variant_ctor(tcx, ctor_def_id);
             }
         }
 
@@ -684,7 +684,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
 
 fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
     let trait_item = tcx.hir().trait_item(trait_item_id);
-    let def_id = trait_item_id.def_id;
+    let def_id = trait_item_id.owner_id;
     tcx.ensure().generics_of(def_id);
 
     match trait_item.kind {
@@ -731,7 +731,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
 }
 
 fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
-    let def_id = impl_item_id.def_id;
+    let def_id = impl_item_id.owner_id;
     tcx.ensure().generics_of(def_id);
     tcx.ensure().type_of(def_id);
     tcx.ensure().predicates_of(def_id);
@@ -751,37 +751,34 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
     }
 }
 
-fn convert_variant_ctor(tcx: TyCtxt<'_>, ctor_id: hir::HirId) {
-    let def_id = tcx.hir().local_def_id(ctor_id);
+fn convert_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     tcx.ensure().generics_of(def_id);
     tcx.ensure().type_of(def_id);
     tcx.ensure().predicates_of(def_id);
 }
 
-fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::Variant<'_>]) {
+fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
     let def = tcx.adt_def(def_id);
     let repr_type = def.repr().discr_type();
     let initial = repr_type.initial_discriminant(tcx);
     let mut prev_discr = None::<Discr<'_>>;
 
     // fill the discriminant values and field types
-    for variant in variants {
+    for variant in def.variants() {
         let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
         prev_discr = Some(
-            if let Some(ref e) = variant.disr_expr {
-                let expr_did = tcx.hir().local_def_id(e.hir_id);
-                def.eval_explicit_discr(tcx, expr_did.to_def_id())
+            if let ty::VariantDiscr::Explicit(const_def_id) = variant.discr {
+                def.eval_explicit_discr(tcx, const_def_id)
             } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
                 Some(discr)
             } else {
-                struct_span_err!(tcx.sess, variant.span, E0370, "enum discriminant overflowed")
-                    .span_label(
-                        variant.span,
-                        format!("overflowed on value after {}", prev_discr.unwrap()),
-                    )
+                let span = tcx.def_span(variant.def_id);
+                struct_span_err!(tcx.sess, span, E0370, "enum discriminant overflowed")
+                    .span_label(span, format!("overflowed on value after {}", prev_discr.unwrap()))
                     .note(&format!(
                         "explicitly set `{} = {}` if that is desired outcome",
-                        variant.ident, wrapped_discr
+                        tcx.item_name(variant.def_id),
+                        wrapped_discr
                     ))
                     .emit();
                 None
@@ -789,17 +786,16 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::V
             .unwrap_or(wrapped_discr),
         );
 
-        for f in variant.data.fields() {
-            let def_id = tcx.hir().local_def_id(f.hir_id);
-            tcx.ensure().generics_of(def_id);
-            tcx.ensure().type_of(def_id);
-            tcx.ensure().predicates_of(def_id);
+        for f in &variant.fields {
+            tcx.ensure().generics_of(f.did);
+            tcx.ensure().type_of(f.did);
+            tcx.ensure().predicates_of(f.did);
         }
 
         // Convert the ctor, if any. This also registers the variant as
         // an item.
-        if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
-            convert_variant_ctor(tcx, ctor_hir_id);
+        if let Some(ctor_def_id) = variant.ctor_def_id {
+            convert_variant_ctor(tcx, ctor_def_id.expect_local());
         }
     }
 }
@@ -1011,7 +1007,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
 
                 match item {
                     Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
-                        if !tcx.impl_defaultness(item.id.def_id).has_value() {
+                        if !tcx.impl_defaultness(item.id.owner_id).has_value() {
                             tcx.sess
                                 .struct_span_err(
                                     item.span,
@@ -1144,7 +1140,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
         }
 
         ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
-            // Do not try to inference the return type for a impl method coming from a trait
+            // Do not try to infer the return type for a impl method coming from a trait
             if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
                 tcx.hir().get(tcx.hir().get_parent_node(hir_id))
                 && i.of_trait.is_some()
@@ -1287,15 +1283,46 @@ fn infer_return_ty_for_fn_sig<'tcx>(
 
 fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
     let icx = ItemCtxt::new(tcx, def_id);
-    match tcx.hir().expect_item(def_id.expect_local()).kind {
+    let item = tcx.hir().expect_item(def_id.expect_local());
+    match item.kind {
         hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
             let selfty = tcx.type_of(def_id);
-            <dyn AstConv<'_>>::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
+            <dyn AstConv<'_>>::instantiate_mono_trait_ref(
+                &icx,
+                ast_trait_ref,
+                selfty,
+                check_impl_constness(tcx, impl_.constness, ast_trait_ref),
+            )
         }),
         _ => bug!(),
     }
 }
 
+fn check_impl_constness(
+    tcx: TyCtxt<'_>,
+    constness: hir::Constness,
+    ast_trait_ref: &hir::TraitRef<'_>,
+) -> ty::BoundConstness {
+    match constness {
+        hir::Constness::Const => {
+            if let Some(trait_def_id) = ast_trait_ref.trait_def_id() && !tcx.has_attr(trait_def_id, sym::const_trait) {
+                let trait_name = tcx.item_name(trait_def_id).to_string();
+                tcx.sess.emit_err(errors::ConstImplForNonConstTrait {
+                    trait_ref_span: ast_trait_ref.path.span,
+                    trait_name,
+                    local_trait_span: trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()),
+                    marking: (),
+                    adding: (),
+                });
+                ty::BoundConstness::NotConst
+            } else {
+                ty::BoundConstness::ConstIfConst
+            }
+        },
+        hir::Constness::NotConst => ty::BoundConstness::NotConst,
+    }
+}
+
 fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> 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());
@@ -2074,12 +2101,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
     // strippable by the linker.
     //
     // Additionally weak lang items have predetermined symbol names.
-    if tcx.is_weak_lang_item(did.to_def_id()) {
+    if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) {
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
     }
-    if let Some(name) = weak_lang_items::link_name(attrs) {
-        codegen_fn_attrs.export_name = Some(name);
-        codegen_fn_attrs.link_name = Some(name);
+    if let Some((name, _)) = lang_items::extract(attrs)
+        && let Some(lang_item) = LangItem::from_name(name)
+        && let Some(link_name) = lang_item.link_name()
+    {
+        codegen_fn_attrs.export_name = Some(link_name);
+        codegen_fn_attrs.link_name = Some(link_name);
     }
     check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
 
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 707fd6c7527..c7777a94689 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -249,6 +249,11 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
     // Now create the real type and const parameters.
     let type_start = own_start - has_self as u32 + params.len() as u32;
     let mut i = 0;
+    let mut next_index = || {
+        let prev = i;
+        i += 1;
+        prev as u32 + type_start
+    };
 
     const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
     `struct`, `enum`, `type`, or `trait` definitions";
@@ -278,15 +283,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
 
             let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
 
-            let param_def = ty::GenericParamDef {
-                index: type_start + i as u32,
+            Some(ty::GenericParamDef {
+                index: next_index(),
                 name: param.name.ident().name,
                 def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
                 pure_wrt_drop: param.pure_wrt_drop,
                 kind,
-            };
-            i += 1;
-            Some(param_def)
+            })
         }
         GenericParamKind::Const { default, .. } => {
             if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
@@ -297,15 +300,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                 );
             }
 
-            let param_def = ty::GenericParamDef {
-                index: type_start + i as u32,
+            Some(ty::GenericParamDef {
+                index: next_index(),
                 name: param.name.ident().name,
                 def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
                 pure_wrt_drop: param.pure_wrt_drop,
                 kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
-            };
-            i += 1;
-            Some(param_def)
+            })
         }
     }));
 
@@ -323,8 +324,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             &["<closure_kind>", "<closure_signature>", "<upvars>"][..]
         };
 
-        params.extend(dummy_args.iter().enumerate().map(|(i, &arg)| ty::GenericParamDef {
-            index: type_start + i as u32,
+        params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
+            index: next_index(),
             name: Symbol::intern(arg),
             def_id,
             pure_wrt_drop: false,
@@ -337,7 +338,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
         let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
         if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
             params.push(ty::GenericParamDef {
-                index: type_start,
+                index: next_index(),
                 name: Symbol::intern("<const_ty>"),
                 def_id,
                 pure_wrt_drop: false,
diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
index c1214698cf7..3f263a6de24 100644
--- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
+++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
@@ -331,8 +331,8 @@ fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetime
 /// `resolve_lifetimes`.
 fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: hir::OwnerId) -> &'tcx ResolveLifetimes {
     let item_id = item_for(tcx, def_id.def_id);
-    let local_def_id = item_id.def_id.def_id;
-    if item_id.def_id == def_id {
+    let local_def_id = item_id.owner_id.def_id;
+    if item_id.owner_id == def_id {
         let item = tcx.hir().item(item_id);
         match item.kind {
             hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(local_def_id),
@@ -557,11 +557,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 // their owner, we can keep going until we find the Item that owns that. We then
                 // conservatively add all resolved lifetimes. Otherwise we run into problems in
                 // cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`.
-                for (_hir_id, node) in self.tcx.hir().parent_iter(item.def_id.into()) {
+                for (_hir_id, node) in self.tcx.hir().parent_iter(item.owner_id.into()) {
                     match node {
                         hir::Node::Item(parent_item) => {
                             let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(
-                                item_for(self.tcx, parent_item.def_id.def_id).def_id.def_id,
+                                item_for(self.tcx, parent_item.owner_id.def_id).owner_id.def_id,
                             );
                             // We need to add *all* deps, since opaque tys may want them from *us*
                             for (&owner, defs) in resolved_lifetimes.defs.iter() {
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index db8f8de68f2..5d1ca1cbd23 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -318,10 +318,10 @@ fn const_evaluatable_predicates_of<'tcx>(
         fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
             let def_id = self.tcx.hir().local_def_id(c.hir_id);
             let ct = ty::Const::from_anon_const(self.tcx, def_id);
-            if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
+            if let ty::ConstKind::Unevaluated(_) = ct.kind() {
                 let span = self.tcx.hir().span(c.hir_id);
                 self.preds.insert((
-                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
+                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
                         .to_predicate(self.tcx),
                     span,
                 ));
@@ -427,6 +427,8 @@ 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 parent_def_id = tcx.hir().get_parent_item(hir_id);
+
             if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() {
                 // In `generics_of` we set the generics' parent to be our parent's parent which means that
                 // we lose out on the predicates of our actual parent if we dont return those predicates here.
@@ -439,8 +441,33 @@ pub(super) fn explicit_predicates_of<'tcx>(
                 //        parent of generics returned by `generics_of`
                 //
                 // In the above code we want the anon const to have predicates in its param env for `T: Trait`
-                let item_def_id = tcx.hir().get_parent_item(hir_id);
-                // In the above code example we would be calling `explicit_predicates_of(Foo)` here
+                // and we would be calling `explicit_predicates_of(Foo)` here
+                return tcx.explicit_predicates_of(parent_def_id);
+            }
+
+            let parent_def_kind = tcx.def_kind(parent_def_id);
+            if matches!(parent_def_kind, DefKind::OpaqueTy) {
+                // In `instantiate_identity` we inherit the predicates of our parent.
+                // However, opaque types do not have a parent (see `gather_explicit_predicates_of`), which means
+                // that we lose out on the predicates of our actual parent if we dont return those predicates here.
+                //
+                //
+                // fn foo<T: Trait>() -> impl Iterator<Output = Another<{ <T as Trait>::ASSOC }> > { todo!() }
+                //                                                        ^^^^^^^^^^^^^^^^^^^ the def id we are calling
+                //                                                                            explicit_predicates_of on
+                //
+                // In the above code we want the anon const to have predicates in its param env for `T: Trait`.
+                // However, the anon const cannot inherit predicates from its parent since it's opaque.
+                //
+                // To fix this, we call `explicit_predicates_of` directly on `foo`, the parent's parent.
+
+                // In the above example this is `foo::{opaque#0}` or `impl Iterator`
+                let parent_hir_id = tcx.hir().local_def_id_to_hir_id(parent_def_id.def_id);
+
+                // In the above example this is the function `foo`
+                let item_def_id = tcx.hir().get_parent_item(parent_hir_id);
+
+                // In the above code example we would be calling `explicit_predicates_of(foo)` here
                 return tcx.explicit_predicates_of(item_def_id);
             }
         }
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 0aa44431c79..c29a645eb4a 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -319,7 +319,15 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     }
                 }
                 ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
-                ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(*self_ty),
+                ItemKind::Impl(hir::Impl { self_ty, .. }) => {
+                    match self_ty.find_self_aliases() {
+                        spans if spans.len() > 0 => {
+                            tcx.sess.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: (), });
+                            tcx.ty_error()
+                        },
+                        _ => icx.to_ty(*self_ty),
+                    }
+                },
                 ItemKind::Fn(..) => {
                     let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
                     tcx.mk_fn_def(def_id.to_def_id(), substs)
@@ -565,6 +573,11 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
         /// checked against it (we also carry the span of that first
         /// type).
         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
+        /// the end that we actually found a type that matches (modulo regions).
+        typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>,
     }
 
     impl ConstraintLocator<'_> {
@@ -591,18 +604,23 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
                 self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() });
                 return;
             }
-            if !tables.concrete_opaque_types.contains_key(&self.def_id) {
+            let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else {
                 debug!("no constraints in typeck results");
                 return;
+            };
+            if self.typeck_types.iter().all(|prev| prev.ty != typeck_hidden_ty.ty) {
+                self.typeck_types.push(typeck_hidden_ty);
             }
+
             // Use borrowck to get the type with unerased regions.
             let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
             debug!(?concrete_opaque_types);
             if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
                 debug!(?concrete_type, "found constraint");
-                if let Some(prev) = self.found {
-                    if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() {
+                if let Some(prev) = &mut self.found {
+                    if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
                         prev.report_mismatch(&concrete_type, self.tcx);
+                        prev.ty = self.tcx.ty_error();
                     }
                 } else {
                     self.found = Some(concrete_type);
@@ -625,31 +643,31 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
             intravisit::walk_expr(self, ex);
         }
         fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
-            trace!(?it.def_id);
+            trace!(?it.owner_id);
             // The opaque type itself or its children are not within its reveal scope.
-            if it.def_id.def_id != self.def_id {
-                self.check(it.def_id.def_id);
+            if it.owner_id.def_id != self.def_id {
+                self.check(it.owner_id.def_id);
                 intravisit::walk_item(self, it);
             }
         }
         fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
-            trace!(?it.def_id);
+            trace!(?it.owner_id);
             // The opaque type itself or its children are not within its reveal scope.
-            if it.def_id.def_id != self.def_id {
-                self.check(it.def_id.def_id);
+            if it.owner_id.def_id != self.def_id {
+                self.check(it.owner_id.def_id);
                 intravisit::walk_impl_item(self, it);
             }
         }
         fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
-            trace!(?it.def_id);
-            self.check(it.def_id.def_id);
+            trace!(?it.owner_id);
+            self.check(it.owner_id.def_id);
             intravisit::walk_trait_item(self, it);
         }
     }
 
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let scope = tcx.hir().get_defining_scope(hir_id);
-    let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None };
+    let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None, typeck_types: vec![] };
 
     debug!(?scope);
 
@@ -679,16 +697,32 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
         }
     }
 
-    match locator.found {
-        Some(hidden) => hidden.ty,
-        None => {
-            tcx.sess.emit_err(UnconstrainedOpaqueType {
-                span: tcx.def_span(def_id),
-                name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
-            });
-            tcx.ty_error()
+    let Some(hidden) = locator.found else {
+        tcx.sess.emit_err(UnconstrainedOpaqueType {
+            span: tcx.def_span(def_id),
+            name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
+            what: match tcx.hir().get(scope) {
+                _ if scope == hir::CRATE_HIR_ID => "module",
+                Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
+                Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl",
+                _ => "item",
+            },
+        });
+        return tcx.ty_error();
+    };
+
+    // Only check against typeck if we didn't already error
+    if !hidden.ty.references_error() {
+        for concrete_type in locator.typeck_types {
+            if tcx.erase_regions(concrete_type.ty) != tcx.erase_regions(hidden.ty)
+                && !(concrete_type, hidden).references_error()
+            {
+                hidden.report_mismatch(&concrete_type, tcx);
+            }
         }
     }
+
+    hidden.ty
 }
 
 fn find_opaque_ty_constraints_for_rpit(
@@ -744,24 +778,24 @@ fn find_opaque_ty_constraints_for_rpit(
             intravisit::walk_expr(self, ex);
         }
         fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
-            trace!(?it.def_id);
+            trace!(?it.owner_id);
             // The opaque type itself or its children are not within its reveal scope.
-            if it.def_id.def_id != self.def_id {
-                self.check(it.def_id.def_id);
+            if it.owner_id.def_id != self.def_id {
+                self.check(it.owner_id.def_id);
                 intravisit::walk_item(self, it);
             }
         }
         fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
-            trace!(?it.def_id);
+            trace!(?it.owner_id);
             // The opaque type itself or its children are not within its reveal scope.
-            if it.def_id.def_id != self.def_id {
-                self.check(it.def_id.def_id);
+            if it.owner_id.def_id != self.def_id {
+                self.check(it.owner_id.def_id);
                 intravisit::walk_impl_item(self, it);
             }
         }
         fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
-            trace!(?it.def_id);
-            self.check(it.def_id.def_id);
+            trace!(?it.owner_id);
+            self.check(it.owner_id.def_id);
             intravisit::walk_trait_item(self, it);
         }
     }
@@ -789,20 +823,15 @@ fn find_opaque_ty_constraints_for_rpit(
             // the `concrete_opaque_types` table.
             tcx.ty_error()
         } else {
-            table
-                .concrete_opaque_types
-                .get(&def_id)
-                .copied()
-                .unwrap_or_else(|| {
-                    // We failed to resolve the opaque type or it
-                    // resolves to itself. We interpret this as the
-                    // no values of the hidden type ever being constructed,
-                    // so we can just make the hidden type be `!`.
-                    // For backwards compatibility reasons, we fall back to
-                    // `()` until we the diverging default is changed.
-                    Some(tcx.mk_diverging_default())
-                })
-                .expect("RPIT always have a hidden type from typeck")
+            table.concrete_opaque_types.get(&def_id).map(|ty| ty.ty).unwrap_or_else(|| {
+                // We failed to resolve the opaque type or it
+                // resolves to itself. We interpret this as the
+                // no values of the hidden type ever being constructed,
+                // so we can just make the hidden type be `!`.
+                // For backwards compatibility reasons, we fall back to
+                // `()` until we the diverging default is changed.
+                tcx.mk_diverging_default()
+            })
         }
     })
 }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index d891171b824..afbb27155a2 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1,24 +1,13 @@
-//! Errors emitted by `hir_analysis`.
+//! Errors emitted by `rustc_hir_analysis`.
 
-use rustc_errors::IntoDiagnostic;
 use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler};
-use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
+use rustc_errors::{IntoDiagnostic, MultiSpan};
+use rustc_macros::{Diagnostic, LintDiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::field_multiply_specified_in_initializer, code = "E0062")]
-pub struct FieldMultiplySpecifiedInInitializer {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[label(hir_analysis::previous_use_label)]
-    pub prev_span: Span,
-    pub ident: Ident,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::unrecognized_atomic_operation, code = "E0092")]
+#[diag(hir_analysis_unrecognized_atomic_operation, code = "E0092")]
 pub struct UnrecognizedAtomicOperation<'a> {
     #[primary_span]
     #[label]
@@ -27,7 +16,7 @@ pub struct UnrecognizedAtomicOperation<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")]
+#[diag(hir_analysis_wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")]
 pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
     #[primary_span]
     #[label]
@@ -38,7 +27,7 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::unrecognized_intrinsic_function, code = "E0093")]
+#[diag(hir_analysis_unrecognized_intrinsic_function, code = "E0093")]
 pub struct UnrecognizedIntrinsicFunction {
     #[primary_span]
     #[label]
@@ -47,19 +36,19 @@ pub struct UnrecognizedIntrinsicFunction {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::lifetimes_or_bounds_mismatch_on_trait, code = "E0195")]
+#[diag(hir_analysis_lifetimes_or_bounds_mismatch_on_trait, code = "E0195")]
 pub struct LifetimesOrBoundsMismatchOnTrait {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(hir_analysis::generics_label)]
+    #[label(generics_label)]
     pub generics_span: Option<Span>,
     pub item_kind: &'static str,
     pub ident: Ident,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::drop_impl_on_wrong_item, code = "E0120")]
+#[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")]
 pub struct DropImplOnWrongItem {
     #[primary_span]
     #[label]
@@ -67,18 +56,18 @@ pub struct DropImplOnWrongItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::field_already_declared, code = "E0124")]
+#[diag(hir_analysis_field_already_declared, code = "E0124")]
 pub struct FieldAlreadyDeclared {
     pub field_name: Ident,
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(hir_analysis::previous_decl_label)]
+    #[label(previous_decl_label)]
     pub prev_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::copy_impl_on_type_with_dtor, code = "E0184")]
+#[diag(hir_analysis_copy_impl_on_type_with_dtor, code = "E0184")]
 pub struct CopyImplOnTypeWithDtor {
     #[primary_span]
     #[label]
@@ -86,14 +75,14 @@ pub struct CopyImplOnTypeWithDtor {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::multiple_relaxed_default_bounds, code = "E0203")]
+#[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")]
 pub struct MultipleRelaxedDefaultBounds {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::copy_impl_on_non_adt, code = "E0206")]
+#[diag(hir_analysis_copy_impl_on_non_adt, code = "E0206")]
 pub struct CopyImplOnNonAdt {
     #[primary_span]
     #[label]
@@ -101,23 +90,23 @@ pub struct CopyImplOnNonAdt {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::trait_object_declared_with_no_traits, code = "E0224")]
+#[diag(hir_analysis_trait_object_declared_with_no_traits, code = "E0224")]
 pub struct TraitObjectDeclaredWithNoTraits {
     #[primary_span]
     pub span: Span,
-    #[label(hir_analysis::alias_span)]
+    #[label(alias_span)]
     pub trait_alias_span: Option<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::ambiguous_lifetime_bound, code = "E0227")]
+#[diag(hir_analysis_ambiguous_lifetime_bound, code = "E0227")]
 pub struct AmbiguousLifetimeBound {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::assoc_type_binding_not_allowed, code = "E0229")]
+#[diag(hir_analysis_assoc_type_binding_not_allowed, code = "E0229")]
 pub struct AssocTypeBindingNotAllowed {
     #[primary_span]
     #[label]
@@ -125,121 +114,36 @@ pub struct AssocTypeBindingNotAllowed {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::functional_record_update_on_non_struct, code = "E0436")]
-pub struct FunctionalRecordUpdateOnNonStruct {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::typeof_reserved_keyword_used, code = "E0516")]
+#[diag(hir_analysis_typeof_reserved_keyword_used, code = "E0516")]
 pub struct TypeofReservedKeywordUsed<'tcx> {
     pub ty: Ty<'tcx>,
     #[primary_span]
     #[label]
     pub span: Span,
-    #[suggestion_verbose(code = "{ty}")]
+    #[suggestion(style = "verbose", code = "{ty}")]
     pub opt_sugg: Option<(Span, Applicability)>,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::return_stmt_outside_of_fn_body, code = "E0572")]
-pub struct ReturnStmtOutsideOfFnBody {
-    #[primary_span]
-    pub span: Span,
-    #[label(hir_analysis::encl_body_label)]
-    pub encl_body_span: Option<Span>,
-    #[label(hir_analysis::encl_fn_label)]
-    pub encl_fn_span: Option<Span>,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::yield_expr_outside_of_generator, code = "E0627")]
-pub struct YieldExprOutsideOfGenerator {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::struct_expr_non_exhaustive, code = "E0639")]
-pub struct StructExprNonExhaustive {
-    #[primary_span]
-    pub span: Span,
-    pub what: &'static str,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::method_call_on_unknown_type, code = "E0699")]
-pub struct MethodCallOnUnknownType {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::value_of_associated_struct_already_specified, code = "E0719")]
+#[diag(hir_analysis_value_of_associated_struct_already_specified, code = "E0719")]
 pub struct ValueOfAssociatedStructAlreadySpecified {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(hir_analysis::previous_bound_label)]
+    #[label(previous_bound_label)]
     pub prev_span: Span,
     pub item_name: Ident,
     pub def_path: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::address_of_temporary_taken, code = "E0745")]
-pub struct AddressOfTemporaryTaken {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Subdiagnostic)]
-pub enum AddReturnTypeSuggestion {
-    #[suggestion(
-        hir_analysis::add_return_type_add,
-        code = "-> {found} ",
-        applicability = "machine-applicable"
-    )]
-    Add {
-        #[primary_span]
-        span: Span,
-        found: String,
-    },
-    #[suggestion(
-        hir_analysis::add_return_type_missing_here,
-        code = "-> _ ",
-        applicability = "has-placeholders"
-    )]
-    MissingHere {
-        #[primary_span]
-        span: Span,
-    },
-}
-
-#[derive(Subdiagnostic)]
-pub enum ExpectedReturnTypeLabel<'tcx> {
-    #[label(hir_analysis::expected_default_return_type)]
-    Unit {
-        #[primary_span]
-        span: Span,
-    },
-    #[label(hir_analysis::expected_return_type)]
-    Other {
-        #[primary_span]
-        span: Span,
-        expected: Ty<'tcx>,
-    },
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::unconstrained_opaque_type)]
+#[diag(hir_analysis_unconstrained_opaque_type)]
 #[note]
 pub struct UnconstrainedOpaqueType {
     #[primary_span]
     pub span: Span,
     pub name: Symbol,
+    pub what: &'static str,
 }
 
 pub struct MissingTypeParams {
@@ -252,10 +156,11 @@ pub struct MissingTypeParams {
 
 // Manual implementation of `IntoDiagnostic` to be able to call `span_to_snippet`.
 impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
+    #[track_caller]
     fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         let mut err = handler.struct_span_err_with_code(
             self.span,
-            rustc_errors::fluent::hir_analysis::missing_type_params,
+            rustc_errors::fluent::hir_analysis_missing_type_params,
             error_code!(E0393),
         );
         err.set_arg("parameterCount", self.missing_type_params.len());
@@ -268,7 +173,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
                 .join(", "),
         );
 
-        err.span_label(self.def_span, rustc_errors::fluent::hir_analysis::label);
+        err.span_label(self.def_span, rustc_errors::fluent::label);
 
         let mut suggested = false;
         // Don't suggest setting the type params if there are some already: the order is
@@ -283,7 +188,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
                 // least we can clue them to the correct syntax `Iterator<Type>`.
                 err.span_suggestion(
                     self.span,
-                    rustc_errors::fluent::hir_analysis::suggestion,
+                    rustc_errors::fluent::suggestion,
                     format!(
                         "{}<{}>",
                         snippet,
@@ -299,16 +204,16 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
             }
         }
         if !suggested {
-            err.span_label(self.span, rustc_errors::fluent::hir_analysis::no_suggestion_label);
+            err.span_label(self.span, rustc_errors::fluent::no_suggestion_label);
         }
 
-        err.note(rustc_errors::fluent::hir_analysis::note);
+        err.note(rustc_errors::fluent::note);
         err
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::manual_implementation, code = "E0183")]
+#[diag(hir_analysis_manual_implementation, code = "E0183")]
 #[help]
 pub struct ManualImplementation {
     #[primary_span]
@@ -318,31 +223,65 @@ pub struct ManualImplementation {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::substs_on_overridden_impl)]
+#[diag(hir_analysis_substs_on_overridden_impl)]
 pub struct SubstsOnOverriddenImpl {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(hir_analysis::unused_extern_crate)]
+#[diag(hir_analysis_unused_extern_crate)]
 pub struct UnusedExternCrate {
     #[suggestion(applicability = "machine-applicable", code = "")]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(hir_analysis::extern_crate_not_idiomatic)]
+#[diag(hir_analysis_extern_crate_not_idiomatic)]
 pub struct ExternCrateNotIdiomatic {
-    #[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")]
+    #[suggestion(
+        style = "short",
+        applicability = "machine-applicable",
+        code = "{suggestion_code}"
+    )]
     pub span: Span,
     pub msg_code: String,
     pub suggestion_code: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::expected_used_symbol)]
+#[diag(hir_analysis_expected_used_symbol)]
 pub struct ExpectedUsedSymbol {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_const_impl_for_non_const_trait)]
+pub struct ConstImplForNonConstTrait {
+    #[primary_span]
+    pub trait_ref_span: Span,
+    pub trait_name: String,
+    #[suggestion(applicability = "machine-applicable", code = "#[const_trait]")]
+    pub local_trait_span: Option<Span>,
+    #[note]
+    pub marking: (),
+    #[note(adding)]
+    pub adding: (),
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_const_bound_for_non_const_trait)]
+pub struct ConstBoundForNonConstTrait {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_self_in_impl_self)]
+pub struct SelfInImplSelf {
+    #[primary_span]
+    pub span: MultiSpan,
+    #[note]
+    pub note: (),
+}
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 69155a422b0..136f6199911 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -11,7 +11,7 @@
 use crate::constrained_generic_params as cgp;
 use min_specialization::check_min_specialization;
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
@@ -19,8 +19,6 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
 use rustc_span::{Span, Symbol};
 
-use std::collections::hash_map::Entry::{Occupied, Vacant};
-
 mod min_specialization;
 
 /// Checks that all the type/lifetime parameters on an impl also
@@ -57,11 +55,10 @@ fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     let min_specialization = tcx.features().min_specialization;
     let module = tcx.hir_module_items(module_def_id);
     for id in module.items() {
-        if matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
-            enforce_impl_params_are_constrained(tcx, id.def_id.def_id);
-            enforce_impl_items_are_distinct(tcx, id.def_id.def_id);
+        if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
+            enforce_impl_params_are_constrained(tcx, id.owner_id.def_id);
             if min_specialization {
-                check_min_specialization(tcx, id.def_id.def_id);
+                check_min_specialization(tcx, id.owner_id.def_id);
             }
         }
     }
@@ -194,38 +191,3 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol
     }
     err.emit();
 }
-
-/// Enforce that we do not have two items in an impl with the same name.
-fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
-    if tcx.impl_trait_ref(impl_def_id).is_some() {
-        return;
-    }
-    let mut seen_type_items = FxHashMap::default();
-    let mut seen_value_items = FxHashMap::default();
-    for &impl_item_ref in tcx.associated_item_def_ids(impl_def_id) {
-        let impl_item = tcx.associated_item(impl_item_ref);
-        let seen_items = match impl_item.kind {
-            ty::AssocKind::Type => &mut seen_type_items,
-            _ => &mut seen_value_items,
-        };
-        let span = tcx.def_span(impl_item_ref);
-        let ident = impl_item.ident(tcx);
-        match seen_items.entry(ident.normalize_to_macros_2_0()) {
-            Occupied(entry) => {
-                let mut err = struct_span_err!(
-                    tcx.sess,
-                    span,
-                    E0201,
-                    "duplicate definitions with name `{}`:",
-                    ident
-                );
-                err.span_label(*entry.get(), format!("previous definition of `{}` here", ident));
-                err.span_label(span, "duplicate definition");
-                err.emit();
-            }
-            Vacant(entry) => {
-                entry.insert(span);
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index b7d9fc8a2fe..bd1a461b935 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -82,20 +82,19 @@ extern crate rustc_middle;
 
 // These are used by Clippy.
 pub mod check;
-pub mod expr_use_visitor;
 
-mod astconv;
+pub mod astconv;
 mod bounds;
 mod check_unused;
 mod coherence;
-mod collect;
+// FIXME: This module shouldn't be public.
+pub mod collect;
 mod constrained_generic_params;
 mod errors;
 pub mod hir_wf_check;
 mod impl_wf_check;
-mod mem_categorization;
 mod outlives;
-mod structured_errors;
+pub mod structured_errors;
 mod variance;
 
 use rustc_errors::{struct_span_err, ErrorGuaranteed};
@@ -107,7 +106,7 @@ use rustc_middle::middle;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::util;
-use rustc_session::config::EntryFnType;
+use rustc_session::{config::EntryFnType, parse::feature_err};
 use rustc_span::{symbol::sym, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
@@ -119,20 +118,40 @@ use astconv::AstConv;
 use bounds::Bounds;
 
 fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
-    match (decl.c_variadic, abi) {
-        // The function has the correct calling convention, or isn't a "C-variadic" function.
-        (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl { .. }) => {}
-        // The function is a "C-variadic" function with an incorrect calling convention.
-        (true, _) => {
-            let mut err = struct_span_err!(
-                tcx.sess,
+    const ERROR_HEAD: &str = "C-variadic function must have a compatible calling convention";
+    const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`";
+    const CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
+    const UNSTABLE_EXPLAIN: &str =
+        "using calling conventions other than `C` or `cdecl` for varargs functions is unstable";
+
+    if !decl.c_variadic || matches!(abi, Abi::C { .. } | Abi::Cdecl { .. }) {
+        return;
+    }
+
+    let extended_abi_support = tcx.features().extended_varargs_abi_support;
+    let conventions = match (extended_abi_support, abi.supports_varargs()) {
+        // User enabled additional ABI support for varargs and function ABI matches those ones.
+        (true, true) => return,
+
+        // Using this ABI would be ok, if the feature for additional ABI support was enabled.
+        // Return CONVENTIONS_STABLE, because we want the other error to look the same.
+        (false, true) => {
+            feature_err(
+                &tcx.sess.parse_sess,
+                sym::extended_varargs_abi_support,
                 span,
-                E0045,
-                "C-variadic function must have C or cdecl calling convention"
-            );
-            err.span_label(span, "C-variadics require C or cdecl calling convention").emit();
+                UNSTABLE_EXPLAIN,
+            )
+            .emit();
+            CONVENTIONS_STABLE
         }
-    }
+
+        (false, false) => CONVENTIONS_STABLE,
+        (true, false) => CONVENTIONS_UNSTABLE,
+    };
+
+    let mut err = struct_span_err!(tcx.sess, span, E0045, "{}, like {}", ERROR_HEAD, conventions);
+    err.span_label(span, ERROR_HEAD).emit();
 }
 
 fn require_same_types<'tcx>(
@@ -382,7 +401,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                         error = true;
                     }
                     if let hir::IsAsync::Async = sig.header.asyncness {
-                        let span = tcx.def_span(it.def_id);
+                        let span = tcx.def_span(it.owner_id);
                         struct_span_err!(
                             tcx.sess,
                             span,
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index 064a70107fe..90c6edb65e4 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -29,7 +29,7 @@ pub(super) fn infer_predicates<'tcx>(
 
         // Visit all the crates and infer predicates
         for id in tcx.hir().items() {
-            let item_did = id.def_id;
+            let item_did = id.owner_id;
 
             debug!("InferVisitor::visit_item(item={:?})", item_did);
 
diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs
index eb0e1203405..fa2ac56593b 100644
--- a/compiler/rustc_hir_analysis/src/outlives/test.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/test.rs
@@ -6,11 +6,11 @@ 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.def_id.to_def_id(), sym::rustc_outlives) {
-            let inferred_outlives_of = tcx.inferred_outlives_of(id.def_id);
+        if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_outlives) {
+            let inferred_outlives_of = tcx.inferred_outlives_of(id.owner_id);
             struct_span_err!(
                 tcx.sess,
-                tcx.def_span(id.def_id),
+                tcx.def_span(id.owner_id),
                 E0640,
                 "{:?}",
                 inferred_outlives_of
diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs
index 2ba87db880b..83ed3e44b3d 100644
--- a/compiler/rustc_hir_analysis/src/variance/test.rs
+++ b/compiler/rustc_hir_analysis/src/variance/test.rs
@@ -6,9 +6,10 @@ 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.def_id.to_def_id(), sym::rustc_variance) {
-            let variances_of = tcx.variances_of(id.def_id);
-            struct_span_err!(tcx.sess, tcx.def_span(id.def_id), E0208, "{:?}", variances_of).emit();
+        if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) {
+            let variances_of = tcx.variances_of(id.owner_id);
+            struct_span_err!(tcx.sess, tcx.def_span(id.owner_id), E0208, "{:?}", variances_of)
+                .emit();
         }
     }
 }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 729139adc2d..da27554a229 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1687,7 +1687,11 @@ impl<'a> State<'a> {
 
             let mut nonelided_generic_args: bool = false;
             let elide_lifetimes = generic_args.args.iter().all(|arg| match arg {
-                GenericArg::Lifetime(lt) => lt.is_elided(),
+                GenericArg::Lifetime(lt) if lt.is_elided() => true,
+                GenericArg::Lifetime(_) => {
+                    nonelided_generic_args = true;
+                    false
+                }
                 _ => {
                     nonelided_generic_args = true;
                     true
diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml
new file mode 100644
index 00000000000..093f9bb8448
--- /dev/null
+++ b/compiler/rustc_hir_typeck/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "rustc_hir_typeck"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+tracing = "0.1"
+rustc_ast = { path = "../rustc_ast" }
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_errors = { path = "../rustc_errors" }
+rustc_graphviz = { path = "../rustc_graphviz" }
+rustc_index = { path = "../rustc_index" }
+rustc_infer = { path = "../rustc_infer" }
+rustc_hir = { path = "../rustc_hir" }
+rustc_hir_analysis = { path = "../rustc_hir_analysis" }
+rustc_hir_pretty = { path = "../rustc_hir_pretty" }
+rustc_lint = { path = "../rustc_lint" }
+rustc_middle = { path = "../rustc_middle" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_serialize = { path = "../rustc_serialize" }
+rustc_session = { path = "../rustc_session" }
+rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
+rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_hir_analysis/src/check/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 143508b785f..2b15d4dcd08 100644
--- a/compiler/rustc_hir_analysis/src/check/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -1,5 +1,5 @@
-use crate::check::coercion::{AsCoercionSite, CoerceMany};
-use crate::check::{Diverges, Expectation, FnCtxt, Needs};
+use crate::coercion::{AsCoercionSite, CoerceMany};
+use crate::{Diverges, Expectation, FnCtxt, Needs};
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::{self as hir, ExprKind};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -514,8 +514,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
 
                 for ty in [first_ty, second_ty] {
-                    for pred in self.tcx.bound_explicit_item_bounds(rpit_def_id).transpose_iter() {
-                        let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx, substs);
+                    for (pred, _) in self
+                        .tcx
+                        .bound_explicit_item_bounds(rpit_def_id)
+                        .subst_iter_copied(self.tcx, substs)
+                    {
                         let pred = match pred.kind().skip_binder() {
                             ty::PredicateKind::Trait(mut trait_pred) => {
                                 assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
diff --git a/compiler/rustc_hir_analysis/src/check/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs
index 59c366ad7d7..59c366ad7d7 100644
--- a/compiler/rustc_hir_analysis/src/check/autoderef.rs
+++ b/compiler/rustc_hir_typeck/src/autoderef.rs
diff --git a/compiler/rustc_hir_analysis/src/check/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index f0a7c910906..1b33f2f02b8 100644
--- a/compiler/rustc_hir_analysis/src/check/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -1,8 +1,8 @@
 use super::method::probe::{IsSuggestion, Mode, ProbeScope};
 use super::method::MethodCallee;
-use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag};
-use crate::type_error_struct;
+use super::{Expectation, FnCtxt, TupleArgumentsFlag};
 
+use crate::type_error_struct;
 use rustc_ast::util::parser::PREC_POSTFIX;
 use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
 use rustc_hir as hir;
@@ -27,6 +27,7 @@ use rustc_span::Span;
 use rustc_target::spec::abi;
 use rustc_trait_selection::autoderef::Autoderef;
 use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::DefIdOrName;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 
 use std::iter;
diff --git a/compiler/rustc_hir_analysis/src/check/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 01badc133c9..7d3129f7ea7 100644
--- a/compiler/rustc_hir_analysis/src/check/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -30,20 +30,18 @@
 
 use super::FnCtxt;
 
-use crate::hir::def_id::DefId;
 use crate::type_error_struct;
-use hir::def_id::LOCAL_CRATE;
 use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
-use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::cast::{CastKind, CastTy};
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Binder, Ty, TypeAndMut, TypeVisitable, VariantDef};
+use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
 use rustc_session::lint;
 use rustc_session::Session;
+use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -62,6 +60,8 @@ pub struct CastCheck<'tcx> {
     cast_ty: Ty<'tcx>,
     cast_span: Span,
     span: Span,
+    /// whether the cast is made in a const context or not.
+    pub constness: hir::Constness,
 }
 
 /// The kind of pointer and associated metadata (thin, length or vtable) - we
@@ -94,10 +94,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         debug!("pointer_kind({:?}, {:?})", t, span);
 
         let t = self.resolve_vars_if_possible(t);
-
-        if let Some(reported) = t.error_reported() {
-            return Err(reported);
-        }
+        t.error_reported()?;
 
         if self.type_is_sized_modulo_regions(self.param_env, t, span) {
             return Ok(Some(PointerKind::Thin));
@@ -204,93 +201,25 @@ fn make_invalid_casting_error<'a, 'tcx>(
     )
 }
 
-pub enum CastCheckResult<'tcx> {
-    Ok,
-    Deferred(CastCheck<'tcx>),
-    Err(ErrorGuaranteed),
-}
-
-pub fn check_cast<'tcx>(
-    fcx: &FnCtxt<'_, 'tcx>,
-    expr: &'tcx hir::Expr<'tcx>,
-    expr_ty: Ty<'tcx>,
-    cast_ty: Ty<'tcx>,
-    cast_span: Span,
-    span: Span,
-) -> CastCheckResult<'tcx> {
-    if cast_ty.is_dyn_star() {
-        check_dyn_star_cast(fcx, expr, expr_ty, cast_ty)
-    } else {
-        match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) {
-            Ok(check) => CastCheckResult::Deferred(check),
-            Err(e) => CastCheckResult::Err(e),
-        }
-    }
-}
-
-fn check_dyn_star_cast<'tcx>(
-    fcx: &FnCtxt<'_, 'tcx>,
-    expr: &'tcx hir::Expr<'tcx>,
-    expr_ty: Ty<'tcx>,
-    cast_ty: Ty<'tcx>,
-) -> CastCheckResult<'tcx> {
-    // Find the bounds in the dyn*. For eaxmple, if we have
-    //
-    //    let x = 22_usize as dyn* (Clone + Debug + 'static)
-    //
-    // this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`.
-    let (existential_predicates, region) = match cast_ty.kind() {
-        ty::Dynamic(predicates, region, ty::DynStar) => (predicates, region),
-        _ => panic!("Invalid dyn* cast_ty"),
-    };
-
-    let cause = ObligationCause::new(
-        expr.span,
-        fcx.body_id,
-        // FIXME(dyn-star): Use a better obligation cause code
-        ObligationCauseCode::MiscObligation,
-    );
-
-    // For each existential predicate (e.g., `?Self: Clone`) substitute
-    // the type of the expression (e.g., `usize` in our example above)
-    // and then require that the resulting predicate (e.g., `usize: Clone`)
-    // holds (it does).
-    for existential_predicate in existential_predicates.iter() {
-        let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty);
-        fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate));
-    }
-
-    // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example).
-    fcx.register_predicate(Obligation::new(
-        cause,
-        fcx.param_env,
-        fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives(
-            ty::OutlivesPredicate(expr_ty, *region),
-        ))),
-    ));
-
-    CastCheckResult::Ok
-}
-
 impl<'a, 'tcx> CastCheck<'tcx> {
-    fn new(
+    pub fn new(
         fcx: &FnCtxt<'a, 'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
         expr_ty: Ty<'tcx>,
         cast_ty: Ty<'tcx>,
         cast_span: Span,
         span: Span,
+        constness: hir::Constness,
     ) -> Result<CastCheck<'tcx>, ErrorGuaranteed> {
         let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span);
-        let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span };
+        let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, constness };
 
         // For better error messages, check for some obviously unsized
         // cases now. We do a more thorough check at the end, once
         // inference is more completely known.
         match cast_ty.kind() {
             ty::Dynamic(_, _, ty::Dyn) | ty::Slice(..) => {
-                let reported = check.report_cast_to_unsized_type(fcx);
-                Err(reported)
+                Err(check.report_cast_to_unsized_type(fcx))
             }
             _ => Ok(check),
         }
@@ -596,7 +525,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 err.emit();
             }
             CastError::SizedUnsizedCast => {
-                use crate::structured_errors::{SizedUnsizedCast, StructuredDiagnostic};
+                use rustc_hir_analysis::structured_errors::{
+                    SizedUnsizedCast, StructuredDiagnostic,
+                };
 
                 SizedUnsizedCast {
                     sess: &fcx.tcx.sess,
@@ -679,10 +610,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     }
 
     fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) -> ErrorGuaranteed {
-        if let Some(reported) =
-            self.cast_ty.error_reported().or_else(|| self.expr_ty.error_reported())
-        {
-            return reported;
+        if let Err(err) = self.cast_ty.error_reported() {
+            return err;
+        }
+        if let Err(err) = self.expr_ty.error_reported() {
+            return err;
         }
 
         let tstr = fcx.ty_to_string(self.cast_ty);
@@ -934,11 +866,13 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
             (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
 
-            // FIXME(dyn-star): this needs more conditions...
-            (_, DynStar) => Ok(CastKind::DynStarCast),
-
-            // FIXME(dyn-star): do we want to allow dyn* upcasting or other casts?
-            (DynStar, _) => Err(CastError::IllegalCast),
+            (_, DynStar) | (DynStar, _) => {
+                if fcx.tcx.features().dyn_star {
+                    bug!("should be handled by `try_coerce`")
+                } else {
+                    Err(CastError::IllegalCast)
+                }
+            }
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
new file mode 100644
index 00000000000..b706d786b52
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -0,0 +1,268 @@
+use crate::coercion::CoerceMany;
+use crate::gather_locals::GatherLocalsVisitor;
+use crate::{FnCtxt, Inherited};
+use crate::{GeneratorTypes, UnsafetyState};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ImplicitSelfKind, ItemKind, Node};
+use rustc_hir_analysis::check::fn_maybe_err;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::RegionVariableOrigin;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::def_id::LocalDefId;
+use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits;
+use std::cell::RefCell;
+
+/// Helper used for fns and closures. Does the grungy work of checking a function
+/// body and returns the function context used for that purpose, since in the case of a fn item
+/// there is still a bit more to do.
+///
+/// * ...
+/// * inherited: other fields inherited from the enclosing fn (if any)
+#[instrument(skip(inherited, body), level = "debug")]
+pub(super) fn check_fn<'a, 'tcx>(
+    inherited: &'a Inherited<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    fn_sig: ty::FnSig<'tcx>,
+    decl: &'tcx hir::FnDecl<'tcx>,
+    fn_id: hir::HirId,
+    body: &'tcx hir::Body<'tcx>,
+    can_be_generator: Option<hir::Movability>,
+    return_type_pre_known: bool,
+) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
+    // Create the function context. This is either derived from scratch or,
+    // in the case of closures, based on the outer context.
+    let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
+    fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
+    fcx.return_type_pre_known = return_type_pre_known;
+
+    let tcx = fcx.tcx;
+    let hir = tcx.hir();
+
+    let declared_ret_ty = fn_sig.output();
+
+    let ret_ty =
+        fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
+            declared_ret_ty,
+            body.value.hir_id,
+            decl.output.span(),
+            param_env,
+        ));
+    // If we replaced declared_ret_ty with infer vars, then we must be inferring
+    // an opaque type, so set a flag so we can improve diagnostics.
+    fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
+
+    fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
+
+    let span = body.value.span;
+
+    fn_maybe_err(tcx, span, fn_sig.abi);
+
+    if fn_sig.abi == Abi::RustCall {
+        let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
+
+        let err = || {
+            let item = match tcx.hir().get(fn_id) {
+                Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
+                Node::ImplItem(hir::ImplItem {
+                    kind: hir::ImplItemKind::Fn(header, ..), ..
+                }) => Some(header),
+                Node::TraitItem(hir::TraitItem {
+                    kind: hir::TraitItemKind::Fn(header, ..),
+                    ..
+                }) => Some(header),
+                // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
+                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
+                node => bug!("Item being checked wasn't a function/closure: {:?}", node),
+            };
+
+            if let Some(header) = item {
+                tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
+            }
+        };
+
+        if fn_sig.inputs().len() != expected_args {
+            err()
+        } else {
+            // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
+            //   This will probably require wide-scale changes to support a TupleKind obligation
+            //   We can't resolve this without knowing the type of the param
+            if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
+                err()
+            }
+        }
+    }
+
+    if body.generator_kind.is_some() && can_be_generator.is_some() {
+        let yield_ty = fcx
+            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
+        fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
+
+        // Resume type defaults to `()` if the generator has no argument.
+        let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
+
+        fcx.resume_yield_tys = Some((resume_ty, yield_ty));
+    }
+
+    GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+    // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
+    // (as it's created inside the body itself, not passed in from outside).
+    let maybe_va_list = if fn_sig.c_variadic {
+        let span = body.params.last().unwrap().span;
+        let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
+        let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
+
+        Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
+    } else {
+        None
+    };
+
+    // Add formal parameters.
+    let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
+    let inputs_fn = fn_sig.inputs().iter().copied();
+    for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
+        // Check the pattern.
+        let ty_span = try { inputs_hir?.get(idx)?.span };
+        fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
+
+        // Check that argument is Sized.
+        // The check for a non-trivial pattern is a hack to avoid duplicate warnings
+        // for simple cases like `fn foo(x: Trait)`,
+        // where we would error once on the parameter as a whole, and once on the binding `x`.
+        if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
+            fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
+        }
+
+        fcx.write_ty(param.hir_id, param_ty);
+    }
+
+    inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
+
+    fcx.in_tail_expr = true;
+    if let ty::Dynamic(..) = declared_ret_ty.kind() {
+        // FIXME: We need to verify that the return type is `Sized` after the return expression has
+        // been evaluated so that we have types available for all the nodes being returned, but that
+        // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
+        // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
+        // while keeping the current ordering we will ignore the tail expression's type because we
+        // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
+        // because we will trigger "unreachable expression" lints unconditionally.
+        // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
+        // case that a newcomer might make, returning a bare trait, and in that case we populate
+        // the tail expression's type so that the suggestion will be correct, but ignore all other
+        // possible cases.
+        fcx.check_expr(&body.value);
+        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+    } else {
+        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+        fcx.check_return_expr(&body.value, false);
+    }
+    fcx.in_tail_expr = false;
+
+    // We insert the deferred_generator_interiors entry after visiting the body.
+    // This ensures that all nested generators appear before the entry of this generator.
+    // resolve_generator_interiors relies on this property.
+    let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
+        let interior = fcx
+            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
+        fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
+
+        let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
+        Some(GeneratorTypes {
+            resume_ty,
+            yield_ty,
+            interior,
+            movability: can_be_generator.unwrap(),
+        })
+    } else {
+        None
+    };
+
+    // Finalize the return check by taking the LUB of the return types
+    // we saw and assigning it to the expected return type. This isn't
+    // really expected to fail, since the coercions would have failed
+    // earlier when trying to find a LUB.
+    let coercion = fcx.ret_coercion.take().unwrap().into_inner();
+    let mut actual_return_ty = coercion.complete(&fcx);
+    debug!("actual_return_ty = {:?}", actual_return_ty);
+    if let ty::Dynamic(..) = declared_ret_ty.kind() {
+        // We have special-cased the case where the function is declared
+        // `-> dyn Foo` and we don't actually relate it to the
+        // `fcx.ret_coercion`, so just substitute a type variable.
+        actual_return_ty =
+            fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
+        debug!("actual_return_ty replaced with {:?}", actual_return_ty);
+    }
+
+    // HACK(oli-obk, compiler-errors): We should be comparing this against
+    // `declared_ret_ty`, but then anything uninferred would be inferred to
+    // the opaque type itself. That again would cause writeback to assume
+    // we have a recursive call site and do the sadly stabilized fallback to `()`.
+    fcx.demand_suptype(span, ret_ty, actual_return_ty);
+
+    // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
+    if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
+        && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
+    {
+        check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
+    }
+
+    (fcx, gen_ty)
+}
+
+fn check_panic_info_fn(
+    tcx: TyCtxt<'_>,
+    fn_id: LocalDefId,
+    fn_sig: ty::FnSig<'_>,
+    decl: &hir::FnDecl<'_>,
+    declared_ret_ty: Ty<'_>,
+) {
+    let Some(panic_info_did) = tcx.lang_items().panic_info() else {
+        tcx.sess.err("language item required, but not found: `panic_info`");
+        return;
+    };
+
+    if *declared_ret_ty.kind() != ty::Never {
+        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+    }
+
+    let inputs = fn_sig.inputs();
+    if inputs.len() != 1 {
+        tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
+        return;
+    }
+
+    let arg_is_panic_info = match *inputs[0].kind() {
+        ty::Ref(region, ty, mutbl) => match *ty.kind() {
+            ty::Adt(ref adt, _) => {
+                adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
+            }
+            _ => false,
+        },
+        _ => false,
+    };
+
+    if !arg_is_panic_info {
+        tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
+    }
+
+    let DefKind::Fn = tcx.def_kind(fn_id) else {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should be a function");
+        return;
+    };
+
+    let generic_counts = tcx.generics_of(fn_id).own_counts();
+    if generic_counts.types != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should have no type parameters");
+    }
+    if generic_counts.consts != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should have no const parameters");
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 84ea06a460b..14f6e7d36be 100644
--- a/compiler/rustc_hir_analysis/src/check/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -2,11 +2,11 @@
 
 use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
 
-use crate::astconv::AstConv;
 use hir::def::DefKind;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 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::{InferOk, InferResult};
@@ -15,6 +15,7 @@ use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::source_map::Span;
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::ArgKind;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use std::cmp;
@@ -176,24 +177,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match *expected_ty.kind() {
             ty::Opaque(def_id, substs) => {
                 let bounds = self.tcx.bound_explicit_item_bounds(def_id);
-                let sig = bounds
-                    .transpose_iter()
-                    .map(|e| e.map_bound(|e| *e).transpose_tuple2())
-                    .find_map(|(pred, span)| match pred.0.kind().skip_binder() {
+                let sig =
+                    bounds.subst_iter_copied(self.tcx, substs).find_map(|(pred, span)| match pred
+                        .kind()
+                        .skip_binder()
+                    {
                         ty::PredicateKind::Projection(proj_predicate) => self
                             .deduce_sig_from_projection(
-                                Some(span.0),
-                                pred.0
-                                    .kind()
-                                    .rebind(pred.rebind(proj_predicate).subst(self.tcx, substs)),
+                                Some(span),
+                                pred.kind().rebind(proj_predicate),
                             ),
                         _ => None,
                     });
 
                 let kind = bounds
-                    .transpose_iter()
-                    .map(|e| e.map_bound(|e| *e).transpose_tuple2())
-                    .filter_map(|(pred, _)| match pred.0.kind().skip_binder() {
+                    .0
+                    .iter()
+                    .filter_map(|(pred, _)| match pred.kind().skip_binder() {
                         ty::PredicateKind::Trait(tp) => {
                             self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
                         }
@@ -226,33 +226,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         expected_vid: ty::TyVid,
     ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
-        let expected_sig =
-            self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| {
-                debug!(?obligation.predicate);
-
-                let bound_predicate = obligation.predicate.kind();
-                if let ty::PredicateKind::Projection(proj_predicate) =
-                    obligation.predicate.kind().skip_binder()
-                {
-                    // Given a Projection predicate, we can potentially infer
-                    // the complete signature.
-                    self.deduce_sig_from_projection(
-                        Some(obligation.cause.span),
-                        bound_predicate.rebind(proj_predicate),
-                    )
-                } else {
-                    None
-                }
-            });
+        let mut expected_sig = None;
+        let mut expected_kind = None;
+
+        for obligation in traits::elaborate_obligations(
+            self.tcx,
+            // Reverse the obligations here, since `elaborate_*` uses a stack,
+            // and we want to keep inference generally in the same order of
+            // the registered obligations.
+            self.obligations_for_self_ty(expected_vid).rev().collect(),
+        ) {
+            debug!(?obligation.predicate);
+            let bound_predicate = obligation.predicate.kind();
+
+            // Given a Projection predicate, we can potentially infer
+            // the complete signature.
+            if expected_sig.is_none()
+                && let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder()
+            {
+                expected_sig = self.deduce_sig_from_projection(
+                    Some(obligation.cause.span),
+                    bound_predicate.rebind(proj_predicate),
+                );
+            }
 
-        // Even if we can't infer the full signature, we may be able to
-        // infer the kind. This can occur when we elaborate a predicate
-        // like `F : Fn<A>`. Note that due to subtyping we could encounter
-        // many viable options, so pick the most restrictive.
-        let expected_kind = self
-            .obligations_for_self_ty(expected_vid)
-            .filter_map(|(tr, _)| self.tcx.fn_trait_kind_from_lang_item(tr.def_id()))
-            .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
+            // Even if we can't infer the full signature, we may be able to
+            // infer the kind. This can occur when we elaborate a predicate
+            // like `F : Fn<A>`. Note that due to subtyping we could encounter
+            // many viable options, so pick the most restrictive.
+            let trait_def_id = match bound_predicate.skip_binder() {
+                ty::PredicateKind::Projection(data) => {
+                    Some(data.projection_ty.trait_def_id(self.tcx))
+                }
+                ty::PredicateKind::Trait(data) => Some(data.def_id()),
+                _ => None,
+            };
+            if let Some(closure_kind) =
+                trait_def_id.and_then(|def_id| self.tcx.fn_trait_kind_from_lang_item(def_id))
+            {
+                expected_kind = Some(
+                    expected_kind
+                        .map_or_else(|| closure_kind, |current| cmp::min(current, closure_kind)),
+                );
+            }
+        }
 
         (expected_sig, expected_kind)
     }
@@ -690,25 +707,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let output_ty = match *ret_ty.kind() {
             ty::Infer(ty::TyVar(ret_vid)) => {
-                self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
+                self.obligations_for_self_ty(ret_vid).find_map(|obligation| {
                     get_future_output(obligation.predicate, obligation.cause.span)
                 })?
             }
             ty::Opaque(def_id, substs) => self
                 .tcx
                 .bound_explicit_item_bounds(def_id)
-                .transpose_iter()
-                .map(|e| e.map_bound(|e| *e).transpose_tuple2())
-                .find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0))?,
+                .subst_iter_copied(self.tcx, substs)
+                .find_map(|(p, s)| get_future_output(p, s))?,
             ty::Error(_) => return None,
             ty::Projection(proj)
                 if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
             {
                 self.tcx
                     .bound_explicit_item_bounds(proj.item_def_id)
-                    .transpose_iter()
-                    .map(|e| e.map_bound(|e| *e).transpose_tuple2())
-                    .find_map(|(p, s)| get_future_output(p.subst(self.tcx, proj.substs), s.0))?
+                    .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),
diff --git a/compiler/rustc_hir_analysis/src/check/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index cf87fe3c510..86597a703e8 100644
--- a/compiler/rustc_hir_analysis/src/check/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -35,8 +35,7 @@
 //! // and are then unable to coerce `&7i32` to `&mut i32`.
 //! ```
 
-use crate::astconv::AstConv;
-use crate::check::FnCtxt;
+use crate::FnCtxt;
 use rustc_errors::{
     struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
 };
@@ -44,6 +43,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 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, TraitEngine, TraitEngineExt};
@@ -216,6 +216,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             ty::Ref(r_b, _, mutbl_b) => {
                 return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b);
             }
+            ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => {
+                return self.coerce_dyn_star(a, b, predicates, region);
+            }
             _ => {}
         }
 
@@ -745,6 +748,63 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         Ok(coercion)
     }
 
+    fn coerce_dyn_star(
+        &self,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+        predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+        b_region: ty::Region<'tcx>,
+    ) -> CoerceResult<'tcx> {
+        if !self.tcx.features().dyn_star {
+            return Err(TypeError::Mismatch);
+        }
+
+        if let ty::Dynamic(a_data, _, _) = a.kind()
+            && let ty::Dynamic(b_data, _, _) = b.kind()
+        {
+            if a_data.principal_def_id() == b_data.principal_def_id() {
+                return self.unify_and(a, b, |_| vec![]);
+            } else if !self.tcx().features().trait_upcasting {
+                let mut err = feature_err(
+                    &self.tcx.sess.parse_sess,
+                    sym::trait_upcasting,
+                    self.cause.span,
+                    &format!(
+                        "cannot cast `{a}` to `{b}`, trait upcasting coercion is experimental"
+                    ),
+                );
+                err.emit();
+            }
+        }
+
+        // Check the obligations of the cast -- for example, when casting
+        // `usize` to `dyn* Clone + 'static`:
+        let obligations = predicates
+            .iter()
+            .map(|predicate| {
+                // For each existential predicate (e.g., `?Self: Clone`) substitute
+                // the type of the expression (e.g., `usize` in our example above)
+                // and then require that the resulting predicate (e.g., `usize: Clone`)
+                // holds (it does).
+                let predicate = predicate.with_self_ty(self.tcx, a);
+                Obligation::new(self.cause.clone(), self.param_env, predicate)
+            })
+            // Enforce the region bound (e.g., `usize: 'static`, in our example).
+            .chain([Obligation::new(
+                self.cause.clone(),
+                self.param_env,
+                self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
+                    ty::OutlivesPredicate(a, b_region),
+                ))),
+            )])
+            .collect();
+
+        Ok(InferOk {
+            value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b),
+            obligations,
+        })
+    }
+
     fn coerce_from_safe_fn<F, G>(
         &self,
         a: Ty<'tcx>,
diff --git a/compiler/rustc_hir_analysis/src/check/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index a5222c92331..16febfc46da 100644
--- a/compiler/rustc_hir_analysis/src/check/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1,21 +1,20 @@
-use crate::check::FnCtxt;
-use rustc_infer::infer::InferOk;
-use rustc_middle::middle::stability::EvalResult;
-use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::ObligationCause;
-
+use crate::FnCtxt;
 use rustc_ast::util::parser::PREC_POSTFIX;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{is_range_literal, Node};
+use rustc_infer::infer::InferOk;
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{BytePos, Span};
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::ObligationCause;
 
 use super::method::probe;
 
@@ -531,24 +530,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         checked_ty: Ty<'tcx>,
         hir_id: hir::HirId,
     ) -> Vec<AssocItem> {
-        let mut methods =
-            self.probe_for_return_type(span, probe::Mode::MethodCall, expected, checked_ty, hir_id);
-        methods.retain(|m| {
-            self.has_only_self_parameter(m)
-                && self
-                    .tcx
-                    // This special internal attribute is used to permit
-                    // "identity-like" conversion methods to be suggested here.
-                    //
-                    // FIXME (#46459 and #46460): ideally
-                    // `std::convert::Into::into` and `std::borrow:ToOwned` would
-                    // also be `#[rustc_conversion_suggestion]`, if not for
-                    // method-probing false-positives and -negatives (respectively).
-                    //
-                    // FIXME? Other potential candidate methods: `as_ref` and
-                    // `as_mut`?
-                    .has_attr(m.def_id, sym::rustc_conversion_suggestion)
-        });
+        let methods = self.probe_for_return_type(
+            span,
+            probe::Mode::MethodCall,
+            expected,
+            checked_ty,
+            hir_id,
+            |m| {
+                self.has_only_self_parameter(m)
+                    && self
+                        .tcx
+                        // This special internal attribute is used to permit
+                        // "identity-like" conversion methods to be suggested here.
+                        //
+                        // FIXME (#46459 and #46460): ideally
+                        // `std::convert::Into::into` and `std::borrow:ToOwned` would
+                        // also be `#[rustc_conversion_suggestion]`, if not for
+                        // method-probing false-positives and -negatives (respectively).
+                        //
+                        // FIXME? Other potential candidate methods: `as_ref` and
+                        // `as_mut`?
+                        .has_attr(m.def_id, sym::rustc_conversion_suggestion)
+            },
+        );
 
         methods
     }
@@ -715,7 +719,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
-    ) -> Option<(Span, String, String, Applicability, bool /* verbose */)> {
+    ) -> Option<(
+        Span,
+        String,
+        String,
+        Applicability,
+        bool, /* verbose */
+        bool, /* suggest `&` or `&mut` type annotation */
+    )> {
         let sess = self.sess();
         let sp = expr.span;
 
@@ -747,6 +758,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     String::new(),
                                     Applicability::MachineApplicable,
                                     true,
+                                    false,
                                 ));
                             }
                         }
@@ -761,6 +773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     "b".to_string(),
                                     Applicability::MachineApplicable,
                                     true,
+                                    false,
                                 ));
                     }
                 }
@@ -818,6 +831,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 sugg.2,
                                 Applicability::MachineApplicable,
                                 false,
+                                false,
                             ));
                         }
 
@@ -845,6 +859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 format!("{prefix}&mut {sugg_expr}"),
                                 Applicability::MachineApplicable,
                                 false,
+                                false,
                             ),
                             hir::Mutability::Not => (
                                 sp,
@@ -852,6 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 format!("{prefix}&{sugg_expr}"),
                                 Applicability::MachineApplicable,
                                 false,
+                                false,
                             ),
                         });
                     }
@@ -881,6 +897,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             String::new(),
                             Applicability::MachineApplicable,
                             true,
+                            true
                         ));
                     }
                     return None;
@@ -894,6 +911,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         String::new(),
                         Applicability::MachineApplicable,
                         true,
+                        true,
                     ));
                 }
             }
@@ -960,6 +978,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             src,
                             applicability,
                             true,
+                            false,
                         ));
                     }
                 }
@@ -1000,6 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 Applicability::MachineApplicable
                             },
                             true,
+                            false,
                         ));
                     }
 
@@ -1051,6 +1071,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             suggestion,
                             Applicability::MachineApplicable,
                             true,
+                            false,
                         ));
                     }
                 }
diff --git a/compiler/rustc_hir_analysis/src/check/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs
index 963a93a95c2..963a93a95c2 100644
--- a/compiler/rustc_hir_analysis/src/check/diverges.rs
+++ b/compiler/rustc_hir_typeck/src/diverges.rs
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
new file mode 100644
index 00000000000..cfb408396da
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -0,0 +1,127 @@
+//! Errors emitted by `rustc_hir_analysis`.
+use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_middle::ty::Ty;
+use rustc_span::{symbol::Ident, Span};
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_field_multiply_specified_in_initializer, code = "E0062")]
+pub struct FieldMultiplySpecifiedInInitializer {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(previous_use_label)]
+    pub prev_span: Span,
+    pub ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_return_stmt_outside_of_fn_body, code = "E0572")]
+pub struct ReturnStmtOutsideOfFnBody {
+    #[primary_span]
+    pub span: Span,
+    #[label(encl_body_label)]
+    pub encl_body_span: Option<Span>,
+    #[label(encl_fn_label)]
+    pub encl_fn_span: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_yield_expr_outside_of_generator, code = "E0627")]
+pub struct YieldExprOutsideOfGenerator {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_struct_expr_non_exhaustive, code = "E0639")]
+pub struct StructExprNonExhaustive {
+    #[primary_span]
+    pub span: Span,
+    pub what: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_method_call_on_unknown_type, code = "E0699")]
+pub struct MethodCallOnUnknownType {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_functional_record_update_on_non_struct, code = "E0436")]
+pub struct FunctionalRecordUpdateOnNonStruct {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_address_of_temporary_taken, code = "E0745")]
+pub struct AddressOfTemporaryTaken {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+pub enum AddReturnTypeSuggestion {
+    #[suggestion(
+        hir_analysis_add_return_type_add,
+        code = "-> {found} ",
+        applicability = "machine-applicable"
+    )]
+    Add {
+        #[primary_span]
+        span: Span,
+        found: String,
+    },
+    #[suggestion(
+        hir_analysis_add_return_type_missing_here,
+        code = "-> _ ",
+        applicability = "has-placeholders"
+    )]
+    MissingHere {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub enum ExpectedReturnTypeLabel<'tcx> {
+    #[label(hir_analysis_expected_default_return_type)]
+    Unit {
+        #[primary_span]
+        span: Span,
+    },
+    #[label(hir_analysis_expected_return_type)]
+    Other {
+        #[primary_span]
+        span: Span,
+        expected: Ty<'tcx>,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_parentheses_in_range, code = "E0689")]
+pub struct MissingParentheseInRange {
+    #[primary_span]
+    #[label(hir_analysis_missing_parentheses_in_range)]
+    pub span: Span,
+    pub ty_str: String,
+    pub method_name: String,
+    #[subdiagnostic]
+    pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    hir_analysis_add_missing_parentheses_in_range,
+    style = "verbose",
+    applicability = "maybe-incorrect"
+)]
+pub struct AddMissingParenthesesInRange {
+    pub func_name: String,
+    #[suggestion_part(code = "(")]
+    pub left: Span,
+    #[suggestion_part(code = ")")]
+    pub right: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/check/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs
index e9e81034477..e9e81034477 100644
--- a/compiler/rustc_hir_analysis/src/check/expectation.rs
+++ b/compiler/rustc_hir_typeck/src/expectation.rs
diff --git a/compiler/rustc_hir_analysis/src/check/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 34c25784597..9fde62a81a1 100644
--- a/compiler/rustc_hir_analysis/src/check/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2,23 +2,22 @@
 //!
 //! See `mod.rs` for more context on type checking in general.
 
-use crate::astconv::AstConv as _;
-use crate::check::cast::{self, CastCheckResult};
-use crate::check::coercion::CoerceMany;
-use crate::check::fatally_break_rust;
-use crate::check::method::SelfSource;
-use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
-use crate::check::{
-    report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs,
-    TupleArgumentsFlag::DontTupleArguments,
-};
+use crate::cast;
+use crate::coercion::CoerceMany;
+use crate::coercion::DynamicCoerceMany;
+use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
 use crate::errors::{
     FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
     YieldExprOutsideOfGenerator,
 };
+use crate::fatally_break_rust;
+use crate::method::SelfSource;
 use crate::type_error_struct;
-
-use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
+use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
+use crate::{
+    report_unexpected_variant_res, BreakableCtxt, Diverges, FnCtxt, Needs,
+    TupleArgumentsFlag::DontTupleArguments,
+};
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -32,6 +31,8 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{Closure, ExprKind, HirId, QPath};
+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::InferOk;
@@ -1130,11 +1131,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         };
 
-        self.check_lhs_assignable(lhs, "E0070", span, |err| {
-            let rhs_ty = self.check_expr(&rhs);
-            suggest_deref_binop(err, rhs_ty);
-        });
-
         // This is (basically) inlined `check_expr_coercable_to_type`, but we want
         // to suggest an additional fixup here in `suggest_deref_binop`.
         let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty);
@@ -1145,6 +1141,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             diag.emit();
         }
 
+        self.check_lhs_assignable(lhs, "E0070", span, |err| {
+            if let Some(rhs_ty) = self.typeck_results.borrow().expr_ty_opt(rhs) {
+                suggest_deref_binop(err, rhs_ty);
+            }
+        });
+
         self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
         if lhs_ty.references_error() || rhs_ty.references_error() {
@@ -1270,9 +1272,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else {
             // Defer other checks until we're done type checking.
             let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
-            match cast::check_cast(self, e, t_expr, t_cast, t.span, expr.span) {
-                CastCheckResult::Ok => t_cast,
-                CastCheckResult::Deferred(cast_check) => {
+            match cast::CastCheck::new(
+                self,
+                e,
+                t_expr,
+                t_cast,
+                t.span,
+                expr.span,
+                self.param_env.constness(),
+            ) {
+                Ok(cast_check) => {
                     debug!(
                         "check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
                         t_cast, t_expr, cast_check,
@@ -1280,7 +1289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     deferred_cast_checks.push(cast_check);
                     t_cast
                 }
-                CastCheckResult::Err(ErrorGuaranteed { .. }) => self.tcx.ty_error(),
+                Err(_) => self.tcx.ty_error(),
             }
         }
     }
@@ -1362,7 +1371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Create a new function context.
         let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id);
-        crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
+        crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
 
         let ty = fcx.check_expr_with_expectation(&body.value, expected);
         fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
@@ -2885,14 +2894,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 }
-
-pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
-    Some(match ty.kind() {
-        ty::Bool => "true",
-        ty::Char => "'a'",
-        ty::Int(_) | ty::Uint(_) => "42",
-        ty::Float(_) => "3.14159",
-        ty::Error(_) | ty::Never => return None,
-        _ => "value",
-    })
-}
diff --git a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index cbc3769901d..fce2a5888ba 100644
--- a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -89,15 +89,6 @@ enum ConsumeMode {
     Move,
 }
 
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum MutateMode {
-    Init,
-    /// Example: `x = y`
-    JustWrite,
-    /// Example: `x += y`
-    WriteAndRead,
-}
-
 /// The ExprUseVisitor type
 ///
 /// This is the code that actually walks the tree.
@@ -583,7 +574,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
         for adjustment in adjustments {
             debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
             match adjustment.kind {
-                adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
+                adjustment::Adjust::NeverToAny
+                | adjustment::Adjust::Pointer(_)
+                | adjustment::Adjust::DynStar => {
                     // Creating a closure/fn-pointer or unsizing consumes
                     // the input and stores it into the resulting rvalue.
                     self.delegate_consume(&place_with_id, place_with_id.hir_id);
diff --git a/compiler/rustc_hir_analysis/src/check/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 4059b3403b1..747ecb036b2 100644
--- a/compiler/rustc_hir_analysis/src/check/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -1,4 +1,4 @@
-use crate::check::FnCtxt;
+use crate::FnCtxt;
 use rustc_data_structures::{
     fx::{FxHashMap, FxHashSet},
     graph::WithSuccessors,
@@ -72,7 +72,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
     //
     // - Unconstrained ints are replaced with `i32`.
     //
-    // - Unconstrained floats are replaced with with `f64`.
+    // - Unconstrained floats are replaced with `f64`.
     //
     // - Non-numerics may get replaced with `()` or `!`, depending on
     //   how they were categorized by `calculate_diverging_fallback`
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index d140c3a0989..7c22eaf18f8 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1,12 +1,7 @@
-use crate::astconv::{
-    AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
-    GenericArgCountResult, IsMethodCall, PathSeg,
-};
-use crate::check::callee::{self, DeferredCallResolution};
-use crate::check::method::{self, MethodCallee, SelfSource};
-use crate::check::rvalue_scopes;
-use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
-
+use crate::callee::{self, DeferredCallResolution};
+use crate::method::{self, MethodCallee, SelfSource};
+use crate::rvalue_scopes;
+use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
@@ -15,6 +10,10 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, GenericArg, Node, QPath};
+use rustc_hir_analysis::astconv::{
+    AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
+    GenericArgCountResult, IsMethodCall, PathSeg,
+};
 use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc_infer::infer::{InferOk, InferResult};
@@ -22,8 +21,8 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMut
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPolyTraitRef,
-    ToPredicate, Ty, UserType,
+    self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPredicate, Ty,
+    UserType,
 };
 use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
 use rustc_session::lint;
@@ -603,9 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut generators = self.deferred_generator_interiors.borrow_mut();
         for (body_id, interior, kind) in generators.drain(..) {
             self.select_obligations_where_possible(false, |_| {});
-            crate::check::generator_interior::resolve_interior(
-                self, def_id, body_id, interior, kind,
-            );
+            crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
         }
     }
 
@@ -653,12 +650,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    fn self_type_matches_expected_vid(
-        &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        expected_vid: ty::TyVid,
-    ) -> bool {
-        let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
+    fn self_type_matches_expected_vid(&self, self_ty: Ty<'tcx>, expected_vid: ty::TyVid) -> bool {
+        let self_ty = self.shallow_resolve(self_ty);
         debug!(?self_ty);
 
         match *self_ty.kind() {
@@ -677,54 +670,61 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn obligations_for_self_ty<'b>(
         &'b self,
         self_ty: ty::TyVid,
-    ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
-    + Captures<'tcx>
-    + 'b {
+    ) -> impl DoubleEndedIterator<Item = traits::PredicateObligation<'tcx>> + Captures<'tcx> + 'b
+    {
         // FIXME: consider using `sub_root_var` here so we
         // can see through subtyping.
         let ty_var_root = self.root_var(self_ty);
         trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations());
 
-        self.fulfillment_cx
-            .borrow()
-            .pending_obligations()
-            .into_iter()
-            .filter_map(move |obligation| {
-                let bound_predicate = obligation.predicate.kind();
-                match bound_predicate.skip_binder() {
-                    ty::PredicateKind::Projection(data) => Some((
-                        bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
-                        obligation,
-                    )),
-                    ty::PredicateKind::Trait(data) => {
-                        Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
-                    }
-                    ty::PredicateKind::Subtype(..) => None,
-                    ty::PredicateKind::Coerce(..) => None,
-                    ty::PredicateKind::RegionOutlives(..) => None,
-                    ty::PredicateKind::TypeOutlives(..) => None,
-                    ty::PredicateKind::WellFormed(..) => None,
-                    ty::PredicateKind::ObjectSafe(..) => None,
-                    ty::PredicateKind::ConstEvaluatable(..) => None,
-                    ty::PredicateKind::ConstEquate(..) => None,
-                    // N.B., this predicate is created by breaking down a
-                    // `ClosureType: FnFoo()` predicate, where
-                    // `ClosureType` represents some `Closure`. It can't
-                    // possibly be referring to the current closure,
-                    // because we haven't produced the `Closure` for
-                    // this closure yet; this is exactly why the other
-                    // code is looking for a self type of an unresolved
-                    // inference variable.
-                    ty::PredicateKind::ClosureKind(..) => None,
-                    ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+        self.fulfillment_cx.borrow().pending_obligations().into_iter().filter_map(
+            move |obligation| match &obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Projection(data)
+                    if self.self_type_matches_expected_vid(
+                        data.projection_ty.self_ty(),
+                        ty_var_root,
+                    ) =>
+                {
+                    Some(obligation)
                 }
-            })
-            .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
+                ty::PredicateKind::Trait(data)
+                    if self.self_type_matches_expected_vid(data.self_ty(), ty_var_root) =>
+                {
+                    Some(obligation)
+                }
+
+                ty::PredicateKind::Trait(..)
+                | ty::PredicateKind::Projection(..)
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Coerce(..)
+                | ty::PredicateKind::RegionOutlives(..)
+                | ty::PredicateKind::TypeOutlives(..)
+                | ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..)
+                // N.B., this predicate is created by breaking down a
+                // `ClosureType: FnFoo()` predicate, where
+                // `ClosureType` represents some `Closure`. It can't
+                // possibly be referring to the current closure,
+                // because we haven't produced the `Closure` for
+                // this closure yet; this is exactly why the other
+                // code is looking for a self type of an unresolved
+                // inference variable.
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+            },
+        )
     }
 
     pub(in super::super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
-        self.obligations_for_self_ty(self_ty)
-            .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait())
+        let sized_did = self.tcx.lang_items().sized_trait();
+        self.obligations_for_self_ty(self_ty).any(|obligation| {
+            match obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Trait(data) => Some(data.def_id()) == sized_did,
+                _ => false,
+            }
+        })
     }
 
     pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
index fc83994caf5..fc83994caf5 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/arg_matrix.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 285db90a9df..8e0fcb56c7f 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1,19 +1,13 @@
-use crate::astconv::AstConv;
-use crate::check::coercion::CoerceMany;
-use crate::check::fn_ctxt::arg_matrix::{
-    ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx,
+use crate::coercion::CoerceMany;
+use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
+use crate::gather_locals::Declaration;
+use crate::method::MethodCallee;
+use crate::Expectation::*;
+use crate::TupleArgumentsFlag::*;
+use crate::{
+    struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs,
+    TupleArgumentsFlag,
 };
-use crate::check::gather_locals::Declaration;
-use crate::check::intrinsicck::InlineAsmCtxt;
-use crate::check::method::MethodCallee;
-use crate::check::Expectation::*;
-use crate::check::TupleArgumentsFlag::*;
-use crate::check::{
-    potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt,
-    LocalTy, Needs, TupleArgumentsFlag,
-};
-use crate::structured_errors::StructuredDiagnostic;
-
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
@@ -21,6 +15,10 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{ExprKind, Node, QPath};
+use rustc_hir_analysis::astconv::AstConv;
+use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
+use rustc_hir_analysis::check::potentially_plural_count;
+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};
@@ -35,16 +33,27 @@ use rustc_span::{self, sym, Span};
 use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
 
 use std::iter;
+use std::mem;
 use std::ops::ControlFlow;
 use std::slice;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub(in super::super) fn check_casts(&self) {
-        let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
+    pub(in super::super) fn check_casts(&mut self) {
+        // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors
+        // when writing to `self.param_env`.
+        let mut deferred_cast_checks = mem::take(&mut *self.deferred_cast_checks.borrow_mut());
+
         debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len());
         for cast in deferred_cast_checks.drain(..) {
+            let prev_env = self.param_env;
+            self.param_env = self.param_env.with_constness(cast.constness);
+
             cast.check(self);
+
+            self.param_env = prev_env;
         }
+
+        *self.deferred_cast_checks.borrow_mut() = deferred_cast_checks;
     }
 
     pub(in super::super) fn check_transmutes(&self) {
@@ -391,7 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     ty: Ty<'tcx>,
                     cast_ty: &str,
                 ) {
-                    use crate::structured_errors::MissingCastForVariadicArg;
+                    use rustc_hir_analysis::structured_errors::MissingCastForVariadicArg;
 
                     MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
                 }
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 51f4cb7e0eb..c36c01e1b46 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -6,12 +6,11 @@ mod suggestions;
 pub use _impl::*;
 pub use suggestions::*;
 
-use crate::astconv::AstConv;
-use crate::check::coercion::DynamicCoerceMany;
-use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
-
+use crate::coercion::DynamicCoerceMany;
+use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::infer;
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -36,7 +35,7 @@ use std::ops::Deref;
 ///
 /// See [`ItemCtxt`]'s docs for more.
 ///
-/// [`ItemCtxt`]: crate::collect::ItemCtxt
+/// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
 /// [`InferCtxt`]: infer::InferCtxt
 pub struct FnCtxt<'a, 'tcx> {
     pub(super) body_id: hir::HirId,
@@ -195,8 +194,8 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         self.tcx
     }
 
-    fn item_def_id(&self) -> Option<DefId> {
-        None
+    fn item_def_id(&self) -> DefId {
+        self.body_id.owner.to_def_id()
     }
 
     fn get_type_parameter_bounds(
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 7a40def177a..4db9c56f98f 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,8 +1,6 @@
 use super::FnCtxt;
-use crate::astconv::AstConv;
-use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
 
-use hir::def_id::DefId;
+use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
 use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
 use rustc_errors::{Applicability, Diagnostic, MultiSpan};
 use rustc_hir as hir;
@@ -11,6 +9,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
     Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
 };
+use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::infer::{self, TyCtxtInferExt};
 use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
@@ -19,6 +18,7 @@ use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::DefIdOrName;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -90,7 +90,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             if ty.is_suggestable(self.tcx, false) {
                                 format!("/* {ty} */")
                             } else {
-                                "".to_string()
+                                "/* value */".to_string()
                             }
                         })
                         .collect::<Vec<_>>()
@@ -102,10 +102,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             let msg = match def_id_or_name {
                 DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
-                    DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct".to_string(),
-                    DefKind::Ctor(CtorOf::Variant, _) => {
-                        "instantiate this tuple variant".to_string()
-                    }
+                    DefKind::Ctor(CtorOf::Struct, _) => "construct this tuple struct".to_string(),
+                    DefKind::Ctor(CtorOf::Variant, _) => "construct this tuple variant".to_string(),
                     kind => format!("call this {}", kind.descr(def_id)),
                 },
                 DefIdOrName::Name(name) => format!("call this {name}"),
@@ -329,7 +327,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
     ) -> bool {
         let expr = expr.peel_blocks();
-        if let Some((sp, msg, suggestion, applicability, verbose)) =
+        if let Some((sp, msg, suggestion, applicability, verbose, annotation)) =
             self.check_ref(expr, found, expected)
         {
             if verbose {
@@ -337,9 +335,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else {
                 err.span_suggestion(sp, &msg, suggestion, applicability);
             }
+            if annotation {
+                let suggest_annotation = match expr.peel_drop_temps().kind {
+                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, _) => "&",
+                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) => "&mut ",
+                    _ => return true,
+                };
+                let mut tuple_indexes = Vec::new();
+                let mut expr_id = expr.hir_id;
+                for (parent_id, node) in self.tcx.hir().parent_iter(expr.hir_id) {
+                    match node {
+                        Node::Expr(&Expr { kind: ExprKind::Tup(subs), .. }) => {
+                            tuple_indexes.push(
+                                subs.iter()
+                                    .enumerate()
+                                    .find(|(_, sub_expr)| sub_expr.hir_id == expr_id)
+                                    .unwrap()
+                                    .0,
+                            );
+                            expr_id = parent_id;
+                        }
+                        Node::Local(local) => {
+                            if let Some(mut ty) = local.ty {
+                                while let Some(index) = tuple_indexes.pop() {
+                                    match ty.kind {
+                                        TyKind::Tup(tys) => ty = &tys[index],
+                                        _ => return true,
+                                    }
+                                }
+                                let annotation_span = ty.span;
+                                err.span_suggestion(
+                                    annotation_span.with_hi(annotation_span.lo()),
+                                    format!("alternatively, consider changing the type annotation"),
+                                    suggest_annotation,
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                            break;
+                        }
+                        _ => break,
+                    }
+                }
+            }
             return true;
-        } else if self.suggest_else_fn_with_closure(err, expr, found, expected)
-        {
+        } else if self.suggest_else_fn_with_closure(err, expr, found, expected) {
             return true;
         } else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
             && let ty::FnDef(def_id, ..) = &found.kind()
@@ -1209,8 +1248,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 }
-
-pub enum DefIdOrName {
-    DefId(DefId),
-    Name(&'static str),
-}
diff --git a/compiler/rustc_hir_analysis/src/check/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 8f34a970f6f..9a096f24fac 100644
--- a/compiler/rustc_hir_analysis/src/check/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -1,9 +1,10 @@
-use crate::check::{FnCtxt, LocalTy, UserType};
+use crate::{FnCtxt, LocalTy};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::PatKind;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::Ty;
+use rustc_middle::ty::UserType;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
 
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index 016f4056bd9..122ad7009cb 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -210,7 +210,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
     }
 
     /// For an expression with an uninhabited return type (e.g. a function that returns !),
-    /// this adds a self edge to to the CFG to model the fact that the function does not
+    /// this adds a self edge to the CFG to model the fact that the function does not
     /// return.
     fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
         let ty = self.typeck_results.expr_ty(expr);
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_propagate.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
index 139d17d2e1c..139d17d2e1c 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_propagate.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs
index c0a0bfe8e1c..c0a0bfe8e1c 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_visualize.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
index 518cd734236..4f3bdfbe758 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
@@ -14,7 +14,7 @@
 
 use self::cfg_build::build_control_flow_graph;
 use self::record_consumed_borrow::find_consumed_and_borrowed;
-use crate::check::FnCtxt;
+use crate::FnCtxt;
 use hir::def_id::DefId;
 use hir::{Body, HirId, HirIdMap, Node};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
index e22675e9d5f..bfe95852aa7 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -1,13 +1,16 @@
 use super::TrackedValue;
 use crate::{
-    check::FnCtxt,
     expr_use_visitor::{self, ExprUseVisitor},
+    FnCtxt,
 };
 use hir::{def_id::DefId, Body, HirId, HirIdMap};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_middle::hir::place::{PlaceBase, Projection, ProjectionKind};
 use rustc_middle::ty::{ParamEnv, TyCtxt};
+use rustc_middle::{
+    hir::place::{PlaceBase, Projection, ProjectionKind},
+    ty::TypeVisitable,
+};
 
 pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
     fcx: &'a FnCtxt<'a, 'tcx>,
@@ -198,7 +201,13 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
 
         // If the type being assigned needs dropped, then the mutation counts as a borrow
         // since it is essentially doing `Drop::drop(&mut x); x = new_value;`.
-        if assignee_place.place.base_ty.needs_drop(self.tcx, self.param_env) {
+        let ty = self.tcx.erase_regions(assignee_place.place.base_ty);
+        if ty.needs_infer() {
+            self.tcx.sess.delay_span_bug(
+                self.tcx.hir().span(assignee_place.hir_id),
+                &format!("inference variables in {ty}"),
+            );
+        } else if ty.needs_drop(self.tcx, self.param_env) {
             self.places
                 .borrowed
                 .insert(TrackedValue::from_place_with_projections_allowed(assignee_place));
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 898419b5b23..b7dd599cd43 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -377,15 +377,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         debug!("is_borrowed_temporary: {:?}", self.drop_ranges.is_borrowed_temporary(expr));
 
         let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr);
-        let may_need_drop = |ty: Ty<'tcx>| {
-            // Avoid ICEs in needs_drop.
-            let ty = self.fcx.resolve_vars_if_possible(ty);
-            let ty = self.fcx.tcx.erase_regions(ty);
-            if ty.needs_infer() {
-                return true;
-            }
-            ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
-        };
 
         // Typically, the value produced by an expression is consumed by its parent in some way,
         // so we only have to check if the parent contains a yield (note that the parent may, for
@@ -403,9 +394,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         // src/test/ui/generator/drop-tracking-parent-expression.rs.
         let scope = if self.drop_ranges.is_borrowed_temporary(expr)
             || ty.map_or(true, |ty| {
-                let needs_drop = may_need_drop(ty);
-                debug!(?needs_drop, ?ty);
-                needs_drop
+                // Avoid ICEs in needs_drop.
+                let ty = self.fcx.resolve_vars_if_possible(ty);
+                let ty = self.fcx.tcx.erase_regions(ty);
+                if ty.needs_infer() {
+                    self.fcx
+                        .tcx
+                        .sess
+                        .delay_span_bug(expr.span, &format!("inference variables in {ty}"));
+                    true
+                } else {
+                    ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
+                }
             }) {
             self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
         } else {
diff --git a/compiler/rustc_hir_analysis/src/check/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs
index 0fb7651b3a1..0fb7651b3a1 100644
--- a/compiler/rustc_hir_analysis/src/check/inherited.rs
+++ b/compiler/rustc_hir_typeck/src/inherited.rs
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
new file mode 100644
index 00000000000..9812d96fcc3
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -0,0 +1,108 @@
+use hir::HirId;
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_index::vec::Idx;
+use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_target::abi::{Pointer, VariantIdx};
+
+use super::FnCtxt;
+
+/// If the type is `Option<T>`, it will return `T`, otherwise
+/// the type itself. Works on most `Option`-like types.
+fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+    let ty::Adt(def, substs) = *ty.kind() else { return ty };
+
+    if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
+        let data_idx;
+
+        let one = VariantIdx::new(1);
+        let zero = VariantIdx::new(0);
+
+        if def.variant(zero).fields.is_empty() {
+            data_idx = one;
+        } else if def.variant(one).fields.is_empty() {
+            data_idx = zero;
+        } else {
+            return ty;
+        }
+
+        if def.variant(data_idx).fields.len() == 1 {
+            return def.variant(data_idx).fields[0].ty(tcx, substs);
+        }
+    }
+
+    ty
+}
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
+        let tcx = self.tcx;
+        let span = tcx.hir().span(hir_id);
+        let normalize = |ty| {
+            let ty = self.resolve_vars_if_possible(ty);
+            self.tcx.normalize_erasing_regions(self.param_env, ty)
+        };
+        let from = normalize(from);
+        let to = normalize(to);
+        trace!(?from, ?to);
+
+        // Transmutes that are only changing lifetimes are always ok.
+        if from == to {
+            return;
+        }
+
+        let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env);
+        let sk_from = skel(from);
+        let sk_to = skel(to);
+        trace!(?sk_from, ?sk_to);
+
+        // Check for same size using the skeletons.
+        if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
+            if sk_from.same_size(sk_to) {
+                return;
+            }
+
+            // Special-case transmuting from `typeof(function)` and
+            // `Option<typeof(function)>` to present a clearer error.
+            let from = unpack_option_like(tcx, from);
+            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) {
+                struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
+                    .note(&format!("source type: {from}"))
+                    .note(&format!("target type: {to}"))
+                    .help("cast with `as` to a pointer instead")
+                    .emit();
+                return;
+            }
+        }
+
+        // Try to display a sensible error with as much information as possible.
+        let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
+            Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
+            Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
+            Err(LayoutError::Unknown(bad)) => {
+                if bad == ty {
+                    "this type does not have a fixed size".to_owned()
+                } else {
+                    format!("size can vary because of {bad}")
+                }
+            }
+            Err(err) => err.to_string(),
+        };
+
+        let mut err = struct_span_err!(
+            tcx.sess,
+            span,
+            E0512,
+            "cannot transmute between types of different sizes, \
+                                        or dependently-sized types"
+        );
+        if from == to {
+            err.note(&format!("`{from}` does not have a fixed size"));
+        } else {
+            err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
+                .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
+        }
+        err.emit();
+    }
+}
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
new file mode 100644
index 00000000000..959c5486645
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -0,0 +1,507 @@
+#![feature(if_let_guard)]
+#![feature(let_chains)]
+#![feature(try_blocks)]
+#![feature(never_type)]
+#![feature(min_specialization)]
+#![feature(control_flow_enum)]
+#![feature(drain_filter)]
+#![allow(rustc::potential_query_instability)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate tracing;
+
+#[macro_use]
+extern crate rustc_middle;
+
+mod _match;
+mod autoderef;
+mod callee;
+// Used by clippy;
+pub mod cast;
+mod check;
+mod closure;
+mod coercion;
+mod demand;
+mod diverges;
+mod errors;
+mod expectation;
+mod expr;
+// Used by clippy;
+pub mod expr_use_visitor;
+mod fallback;
+mod fn_ctxt;
+mod gather_locals;
+mod generator_interior;
+mod inherited;
+mod intrinsicck;
+mod mem_categorization;
+mod method;
+mod op;
+mod pat;
+mod place_op;
+mod rvalue_scopes;
+mod upvar;
+mod writeback;
+
+pub use diverges::Diverges;
+pub use expectation::Expectation;
+pub use fn_ctxt::*;
+pub use inherited::{Inherited, InheritedBuilder};
+
+use crate::check::check_fn;
+use crate::coercion::DynamicCoerceMany;
+use crate::gather_locals::GatherLocalsVisitor;
+use rustc_data_structures::unord::UnordSet;
+use rustc_errors::{struct_span_err, MultiSpan};
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{HirIdMap, Node};
+use rustc_hir_analysis::astconv::AstConv;
+use rustc_hir_analysis::check::check_abi;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_middle::traits;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::config;
+use rustc_session::Session;
+use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::Span;
+
+#[macro_export]
+macro_rules! type_error_struct {
+    ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
+        let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
+
+        if $typ.references_error() {
+            err.downgrade_to_delayed_bug();
+        }
+
+        err
+    })
+}
+
+/// The type of a local binding, including the revealed type for anon types.
+#[derive(Copy, Clone, Debug)]
+pub struct LocalTy<'tcx> {
+    decl_ty: Ty<'tcx>,
+    revealed_ty: Ty<'tcx>,
+}
+
+#[derive(Copy, Clone)]
+pub struct UnsafetyState {
+    pub def: hir::HirId,
+    pub unsafety: hir::Unsafety,
+    from_fn: bool,
+}
+
+impl UnsafetyState {
+    pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
+        UnsafetyState { def, unsafety, from_fn: true }
+    }
+
+    pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
+        use hir::BlockCheckMode;
+        match self.unsafety {
+            // If this unsafe, then if the outer function was already marked as
+            // unsafe we shouldn't attribute the unsafe'ness to the block. This
+            // way the block can be warned about instead of ignoring this
+            // extraneous block (functions are never warned about).
+            hir::Unsafety::Unsafe if self.from_fn => self,
+
+            unsafety => {
+                let (unsafety, def) = match blk.rules {
+                    BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
+                    BlockCheckMode::DefaultBlock => (unsafety, self.def),
+                };
+                UnsafetyState { def, unsafety, from_fn: false }
+            }
+        }
+    }
+}
+
+/// If this `DefId` is a "primary tables entry", returns
+/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
+///
+/// If this function returns `Some`, then `typeck_results(def_id)` will
+/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
+/// may not succeed. In some cases where this function returns `None`
+/// (notably closures), `typeck_results(def_id)` would wind up
+/// redirecting to the owning function.
+fn primary_body_of(
+    tcx: TyCtxt<'_>,
+    id: hir::HirId,
+) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
+    match tcx.hir().get(id) {
+        Node::Item(item) => match item.kind {
+            hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
+                Some((body, Some(ty), None))
+            }
+            hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
+            _ => None,
+        },
+        Node::TraitItem(item) => match item.kind {
+            hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
+            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
+                Some((body, None, Some(sig)))
+            }
+            _ => None,
+        },
+        Node::ImplItem(item) => match item.kind {
+            hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
+            hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
+            _ => None,
+        },
+        Node::AnonConst(constant) => Some((constant.body, None, None)),
+        _ => None,
+    }
+}
+
+fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    // Closures' typeck results come from their outermost function,
+    // as they are part of the same "inference environment".
+    let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+    if typeck_root_def_id != def_id {
+        return tcx.has_typeck_results(typeck_root_def_id);
+    }
+
+    if let Some(def_id) = def_id.as_local() {
+        let id = tcx.hir().local_def_id_to_hir_id(def_id);
+        primary_body_of(tcx, id).is_some()
+    } else {
+        false
+    }
+}
+
+fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDefId> {
+    &*tcx.typeck(def_id).used_trait_imports
+}
+
+fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
+    tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
+}
+
+fn typeck_const_arg<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (did, param_did): (LocalDefId, DefId),
+) -> &ty::TypeckResults<'tcx> {
+    let fallback = move || tcx.type_of(param_did);
+    typeck_with_fallback(tcx, did, fallback)
+}
+
+fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
+    if let Some(param_did) = tcx.opt_const_param_of(def_id) {
+        tcx.typeck_const_arg((def_id, param_did))
+    } else {
+        let fallback = move || tcx.type_of(def_id.to_def_id());
+        typeck_with_fallback(tcx, def_id, fallback)
+    }
+}
+
+/// Used only to get `TypeckResults` for type inference during error recovery.
+/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
+fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
+    let fallback = move || {
+        let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
+        tcx.ty_error_with_message(span, "diagnostic only typeck table used")
+    };
+    typeck_with_fallback(tcx, def_id, fallback)
+}
+
+fn typeck_with_fallback<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    fallback: impl Fn() -> Ty<'tcx> + 'tcx,
+) -> &'tcx ty::TypeckResults<'tcx> {
+    // Closures' typeck results come from their outermost function,
+    // as they are part of the same "inference environment".
+    let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+    if typeck_root_def_id != def_id {
+        return tcx.typeck(typeck_root_def_id);
+    }
+
+    let id = tcx.hir().local_def_id_to_hir_id(def_id);
+    let span = tcx.hir().span(id);
+
+    // Figure out what primary body this item has.
+    let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
+        span_bug!(span, "can't type-check body of {:?}", def_id);
+    });
+    let body = tcx.hir().body(body_id);
+
+    let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
+        let param_env = tcx.param_env(def_id);
+        let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
+            let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
+                let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
+                <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
+            } else {
+                tcx.fn_sig(def_id)
+            };
+
+            check_abi(tcx, id, span, fn_sig.abi());
+
+            // Compute the function signature from point of view of inside the fn.
+            let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
+            let fn_sig = inh.normalize_associated_types_in(
+                body.value.span,
+                body_id.hir_id,
+                param_env,
+                fn_sig,
+            );
+            check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
+        } else {
+            let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
+            let expected_type = body_ty
+                .and_then(|ty| match ty.kind {
+                    hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
+                    _ => None,
+                })
+                .unwrap_or_else(|| match tcx.hir().get(id) {
+                    Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
+                        Node::Expr(&hir::Expr {
+                            kind: hir::ExprKind::ConstBlock(ref anon_const),
+                            ..
+                        }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::TypeInference,
+                            span,
+                        }),
+                        Node::Ty(&hir::Ty {
+                            kind: hir::TyKind::Typeof(ref anon_const), ..
+                        }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::TypeInference,
+                            span,
+                        }),
+                        Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
+                        | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
+                            let operand_ty = asm
+                                .operands
+                                .iter()
+                                .filter_map(|(op, _op_sp)| match op {
+                                    hir::InlineAsmOperand::Const { anon_const }
+                                        if anon_const.hir_id == id =>
+                                    {
+                                        // Inline assembly constants must be integers.
+                                        Some(fcx.next_int_var())
+                                    }
+                                    hir::InlineAsmOperand::SymFn { anon_const }
+                                        if anon_const.hir_id == id =>
+                                    {
+                                        Some(fcx.next_ty_var(TypeVariableOrigin {
+                                            kind: TypeVariableOriginKind::MiscVariable,
+                                            span,
+                                        }))
+                                    }
+                                    _ => None,
+                                })
+                                .next();
+                            operand_ty.unwrap_or_else(fallback)
+                        }
+                        _ => fallback(),
+                    },
+                    _ => fallback(),
+                });
+
+            let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
+            fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
+
+            // Gather locals in statics (because of block expressions).
+            GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+            fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
+
+            fcx.write_ty(id, expected_type);
+
+            fcx
+        };
+
+        let fallback_has_occurred = fcx.type_inference_fallback();
+
+        // Even though coercion casts provide type hints, we check casts after fallback for
+        // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
+        fcx.check_casts();
+        fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
+
+        // Closure and generator analysis may run after fallback
+        // because they don't constrain other type variables.
+        // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
+        let prev_constness = fcx.param_env.constness();
+        fcx.param_env = fcx.param_env.without_const();
+        fcx.closure_analyze(body);
+        fcx.param_env = fcx.param_env.with_constness(prev_constness);
+        assert!(fcx.deferred_call_resolutions.borrow().is_empty());
+        // Before the generator analysis, temporary scopes shall be marked to provide more
+        // precise information on types to be captured.
+        fcx.resolve_rvalue_scopes(def_id.to_def_id());
+        fcx.resolve_generator_interiors(def_id.to_def_id());
+
+        for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
+            let ty = fcx.normalize_ty(span, ty);
+            fcx.require_type_is_sized(ty, span, code);
+        }
+
+        fcx.select_all_obligations_or_error();
+
+        if !fcx.infcx.is_tainted_by_errors() {
+            fcx.check_transmutes();
+        }
+
+        fcx.check_asms();
+
+        fcx.infcx.skip_region_resolution();
+
+        fcx.resolve_type_vars_in_body(body)
+    });
+
+    // Consistency check our TypeckResults instance can hold all ItemLocalIds
+    // it will need to hold.
+    assert_eq!(typeck_results.hir_owner, id.owner);
+
+    typeck_results
+}
+
+/// When `check_fn` is invoked on a generator (i.e., a body that
+/// includes yield), it returns back some information about the yield
+/// points.
+struct GeneratorTypes<'tcx> {
+    /// Type of generator argument / values returned by `yield`.
+    resume_ty: Ty<'tcx>,
+
+    /// Type of value that is yielded.
+    yield_ty: Ty<'tcx>,
+
+    /// Types that are captured (see `GeneratorInterior` for more).
+    interior: Ty<'tcx>,
+
+    /// Indicates if the generator is movable or static (immovable).
+    movability: hir::Movability,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum Needs {
+    MutPlace,
+    None,
+}
+
+impl Needs {
+    fn maybe_mut_place(m: hir::Mutability) -> Self {
+        match m {
+            hir::Mutability::Mut => Needs::MutPlace,
+            hir::Mutability::Not => Needs::None,
+        }
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum PlaceOp {
+    Deref,
+    Index,
+}
+
+pub struct BreakableCtxt<'tcx> {
+    may_break: bool,
+
+    // this is `null` for loops where break with a value is illegal,
+    // such as `while`, `for`, and `while let`
+    coerce: Option<DynamicCoerceMany<'tcx>>,
+}
+
+pub struct EnclosingBreakables<'tcx> {
+    stack: Vec<BreakableCtxt<'tcx>>,
+    by_id: HirIdMap<usize>,
+}
+
+impl<'tcx> EnclosingBreakables<'tcx> {
+    fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
+        self.opt_find_breakable(target_id).unwrap_or_else(|| {
+            bug!("could not find enclosing breakable with id {}", target_id);
+        })
+    }
+
+    fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
+        match self.by_id.get(&target_id) {
+            Some(ix) => Some(&mut self.stack[*ix]),
+            None => None,
+        }
+    }
+}
+
+fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
+    struct_span_err!(
+        tcx.sess,
+        span,
+        E0533,
+        "expected unit struct, unit variant or constant, found {} `{}`",
+        res.descr(),
+        rustc_hir_pretty::qpath_to_string(qpath),
+    )
+    .emit();
+}
+
+/// Controls whether the arguments are tupled. This is used for the call
+/// operator.
+///
+/// Tupling means that all call-side arguments are packed into a tuple and
+/// passed as a single parameter. For example, if tupling is enabled, this
+/// function:
+/// ```
+/// fn f(x: (isize, isize)) {}
+/// ```
+/// Can be called as:
+/// ```ignore UNSOLVED (can this be done in user code?)
+/// # fn f(x: (isize, isize)) {}
+/// f(1, 2);
+/// ```
+/// Instead of:
+/// ```
+/// # fn f(x: (isize, isize)) {}
+/// f((1, 2));
+/// ```
+#[derive(Clone, Eq, PartialEq)]
+enum TupleArgumentsFlag {
+    DontTupleArguments,
+    TupleArguments,
+}
+
+fn fatally_break_rust(sess: &Session) {
+    let handler = sess.diagnostic();
+    handler.span_bug_no_panic(
+        MultiSpan::new(),
+        "It looks like you're trying to break rust; would you like some ICE?",
+    );
+    handler.note_without_error("the compiler expectedly panicked. this is a feature.");
+    handler.note_without_error(
+        "we would appreciate a joke overview: \
+         https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
+    );
+    handler.note_without_error(&format!(
+        "rustc {} running on {}",
+        option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+        config::host_triple(),
+    ));
+}
+
+fn has_expected_num_generic_args<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_did: Option<DefId>,
+    expected: usize,
+) -> bool {
+    trait_did.map_or(true, |trait_did| {
+        let generics = tcx.generics_of(trait_did);
+        generics.count() == expected + if generics.has_self { 1 } else { 0 }
+    })
+}
+
+pub fn provide(providers: &mut Providers) {
+    method::provide(providers);
+    *providers = Providers {
+        typeck_item_bodies,
+        typeck_const_arg,
+        typeck,
+        diagnostic_only_typeck,
+        has_typeck_results,
+        used_trait_imports,
+        ..*providers
+    };
+}
diff --git a/compiler/rustc_hir_analysis/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index b62c5b5e077..362f1c34300 100644
--- a/compiler/rustc_hir_analysis/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -292,7 +292,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
 
             adjustment::Adjust::NeverToAny
             | adjustment::Adjust::Pointer(_)
-            | adjustment::Adjust::Borrow(_) => {
+            | adjustment::Adjust::Borrow(_)
+            | adjustment::Adjust::DynStar => {
                 // Result is an rvalue.
                 Ok(self.cat_rvalue(expr.hir_id, expr.span, target))
             }
diff --git a/compiler/rustc_hir_analysis/src/check/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 30731cbd03d..be4ea998622 100644
--- a/compiler/rustc_hir_analysis/src/check/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -1,10 +1,10 @@
 use super::{probe, MethodCallee};
 
-use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
-use crate::check::{callee, FnCtxt};
+use crate::{callee, FnCtxt};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
+use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
 use rustc_infer::infer::{self, InferOk};
 use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
diff --git a/compiler/rustc_hir_analysis/src/check/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 3fe9bea2299..a1278edefbb 100644
--- a/compiler/rustc_hir_analysis/src/check/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -10,14 +10,14 @@ mod suggest;
 pub use self::suggest::SelfSource;
 pub use self::MethodError::*;
 
-use crate::check::{Expectation, FnCtxt};
-use crate::ObligationCause;
+use crate::{Expectation, FnCtxt};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace};
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{self, InferOk};
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
 use rustc_span::symbol::Ident;
diff --git a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
index ca4cdf5a0d0..3c98a2aa3ab 100644
--- a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
@@ -1,3 +1,7 @@
+use crate::{
+    method::probe::{self, Pick},
+    FnCtxt,
+};
 use hir::def_id::DefId;
 use hir::HirId;
 use hir::ItemKind;
@@ -12,11 +16,6 @@ use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
 
-use crate::check::{
-    method::probe::{self, Pick},
-    FnCtxt,
-};
-
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(super) fn lint_dot_call_from_2018(
         &self,
diff --git a/compiler/rustc_hir_analysis/src/check/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index ba078ad0abb..28aa2302f88 100644
--- a/compiler/rustc_hir_analysis/src/check/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -3,14 +3,12 @@ use super::CandidateSource;
 use super::MethodError;
 use super::NoMatchData;
 
-use crate::check::FnCtxt;
 use crate::errors::MethodCallOnUnknownType;
-use crate::hir::def::DefKind;
-use crate::hir::def_id::DefId;
-
+use crate::FnCtxt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def::Namespace;
 use rustc_infer::infer::canonical::OriginalQueryValues;
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
@@ -23,6 +21,7 @@ use rustc_middle::ty::GenericParamDefKind;
 use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
 use rustc_session::lint;
+use rustc_span::def_id::DefId;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::lev_distance::{
     find_best_match_for_name_with_substrings, lev_distance_with_substrings,
@@ -253,7 +252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// would result in an error (basically, the same criteria we
     /// would use to decide if a method is a plausible fit for
     /// ambiguity purposes).
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self, candidate_filter))]
     pub fn probe_for_return_type(
         &self,
         span: Span,
@@ -261,6 +260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         return_type: Ty<'tcx>,
         self_ty: Ty<'tcx>,
         scope_expr_id: hir::HirId,
+        candidate_filter: impl Fn(&ty::AssocItem) -> bool,
     ) -> Vec<ty::AssocItem> {
         let method_names = self
             .probe_op(
@@ -272,7 +272,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self_ty,
                 scope_expr_id,
                 ProbeScope::AllTraits,
-                |probe_cx| Ok(probe_cx.candidate_method_names()),
+                |probe_cx| Ok(probe_cx.candidate_method_names(candidate_filter)),
             )
             .unwrap_or_default();
         method_names
@@ -967,12 +967,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         }
     }
 
-    fn candidate_method_names(&self) -> Vec<Ident> {
+    fn candidate_method_names(
+        &self,
+        candidate_filter: impl Fn(&ty::AssocItem) -> bool,
+    ) -> Vec<Ident> {
         let mut set = FxHashSet::default();
         let mut names: Vec<_> = self
             .inherent_candidates
             .iter()
             .chain(&self.extension_candidates)
+            .filter(|candidate| candidate_filter(&candidate.item))
             .filter(|candidate| {
                 if let Some(return_ty) = self.return_type {
                     self.matches_return_type(&candidate.item, None, return_ty)
@@ -1690,7 +1694,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             pcx.allow_similar_names = true;
             pcx.assemble_inherent_candidates();
 
-            let method_names = pcx.candidate_method_names();
+            let method_names = pcx.candidate_method_names(|_| true);
             pcx.allow_similar_names = false;
             let applicable_close_candidates: Vec<ty::AssocItem> = method_names
                 .iter()
diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index e276c4f7d84..6c21ed902d0 100644
--- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1,7 +1,8 @@
 //! Give useful errors and suggestions to users when an item can't be
 //! found or is otherwise invalid.
 
-use crate::check::FnCtxt;
+use crate::errors;
+use crate::FnCtxt;
 use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{
@@ -105,7 +106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let report_candidates = |span: Span,
                                  err: &mut Diagnostic,
-                                 mut sources: Vec<CandidateSource>,
+                                 sources: &mut Vec<CandidateSource>,
                                  sugg_span: Span| {
             sources.sort();
             sources.dedup();
@@ -247,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         match error {
             MethodError::NoMatch(NoMatchData {
-                static_candidates: static_sources,
+                static_candidates: mut static_sources,
                 unsatisfied_predicates,
                 out_of_scope_traits,
                 lev_candidate,
@@ -271,7 +272,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 };
 
-                if self.suggest_constraining_numerical_ty(
+                if self.suggest_wrapping_range_with_parens(
+                    tcx, actual, source, span, item_name, &ty_str,
+                ) || self.suggest_constraining_numerical_ty(
                     tcx, actual, source, span, item_kind, item_name, &ty_str,
                 ) {
                     return None;
@@ -419,9 +422,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         err.help(&format!("try with `{}::{}`", ty_str, item_name,));
                     }
 
-                    report_candidates(span, &mut err, static_sources, sugg_span);
+                    report_candidates(span, &mut err, &mut static_sources, sugg_span);
                 } else if static_sources.len() > 1 {
-                    report_candidates(span, &mut err, static_sources, sugg_span);
+                    report_candidates(span, &mut err, &mut static_sources, sugg_span);
                 }
 
                 let mut bound_spans = vec![];
@@ -1004,6 +1007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         source,
                         out_of_scope_traits,
                         &unsatisfied_predicates,
+                        &static_sources,
                         unsatisfied_bounds,
                     );
                 }
@@ -1076,7 +1080,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return Some(err);
             }
 
-            MethodError::Ambiguity(sources) => {
+            MethodError::Ambiguity(mut sources) => {
                 let mut err = struct_span_err!(
                     self.sess(),
                     item_name.span,
@@ -1085,7 +1089,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
                 err.span_label(item_name.span, format!("multiple `{}` found", item_name));
 
-                report_candidates(span, &mut err, sources, sugg_span);
+                report_candidates(span, &mut err, &mut sources, sugg_span);
                 err.emit();
             }
 
@@ -1202,6 +1206,89 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         false
     }
 
+    /// Suggest possible range with adding parentheses, for example:
+    /// when encountering `0..1.map(|i| i + 1)` suggest `(0..1).map(|i| i + 1)`.
+    fn suggest_wrapping_range_with_parens(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        actual: Ty<'tcx>,
+        source: SelfSource<'tcx>,
+        span: Span,
+        item_name: Ident,
+        ty_str: &str,
+    ) -> bool {
+        if let SelfSource::MethodCall(expr) = source {
+            for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
+                if let Node::Expr(parent_expr) = parent {
+                    let lang_item = match parent_expr.kind {
+                        ExprKind::Struct(ref qpath, _, _) => match **qpath {
+                            QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
+                            QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
+                            QPath::LangItem(LangItem::RangeToInclusive, ..) => {
+                                Some(LangItem::RangeToInclusive)
+                            }
+                            _ => None,
+                        },
+                        ExprKind::Call(ref func, _) => match func.kind {
+                            // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+                            ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => {
+                                Some(LangItem::RangeInclusiveStruct)
+                            }
+                            _ => None,
+                        },
+                        _ => None,
+                    };
+
+                    if lang_item.is_none() {
+                        continue;
+                    }
+
+                    let span_included = match parent_expr.kind {
+                        hir::ExprKind::Struct(_, eps, _) => {
+                            eps.len() > 0 && eps.last().map_or(false, |ep| ep.span.contains(span))
+                        }
+                        // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+                        hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
+                        _ => false,
+                    };
+
+                    if !span_included {
+                        continue;
+                    }
+
+                    let range_def_id = self.tcx.require_lang_item(lang_item.unwrap(), None);
+                    let range_ty =
+                        self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]);
+
+                    let pick = self.probe_for_name(
+                        span,
+                        Mode::MethodCall,
+                        item_name,
+                        IsSuggestion(true),
+                        range_ty,
+                        expr.hir_id,
+                        ProbeScope::AllTraits,
+                    );
+                    if pick.is_ok() {
+                        let range_span = parent_expr.span.with_hi(expr.span.hi());
+                        tcx.sess.emit_err(errors::MissingParentheseInRange {
+                            span,
+                            ty_str: ty_str.to_string(),
+                            method_name: item_name.as_str().to_string(),
+                            add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
+                                func_name: item_name.name.as_str().to_string(),
+                                left: range_span.shrink_to_lo(),
+                                right: range_span.shrink_to_hi(),
+                            }),
+                        });
+                        return true;
+                    }
+                }
+            }
+        }
+        false
+    }
+
     fn suggest_constraining_numerical_ty(
         &self,
         tcx: TyCtxt<'tcx>,
@@ -1264,7 +1351,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // If this is a floating point literal that ends with '.',
                     // get rid of it to stop this from becoming a member access.
                     let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
-
                     err.span_suggestion(
                         lit.span,
                         &format!(
@@ -1930,6 +2016,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Option<ty::Predicate<'tcx>>,
             Option<ObligationCause<'tcx>>,
         )],
+        static_candidates: &[CandidateSource],
         unsatisfied_bounds: bool,
     ) {
         let mut alt_rcvr_sugg = false;
@@ -2044,6 +2131,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 None => true,
             })
             .filter(|info| {
+                // Static candidates are already implemented, and known not to work
+                // Do not suggest them again
+                static_candidates.iter().all(|sc| match *sc {
+                    CandidateSource::Trait(def_id) => def_id != info.def_id,
+                    CandidateSource::Impl(def_id) => {
+                        self.tcx.trait_id_of_impl(def_id) != Some(info.def_id)
+                    }
+                })
+            })
+            .filter(|info| {
                 // We approximate the coherence rules to only suggest
                 // traits that are legal to implement by requiring that
                 // either the type or trait is local. Multi-dispatch means
diff --git a/compiler/rustc_hir_analysis/src/check/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 5e498a92ec2..89573997693 100644
--- a/compiler/rustc_hir_analysis/src/check/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -2,7 +2,7 @@
 
 use super::method::MethodCallee;
 use super::{has_expected_num_generic_args, FnCtxt};
-use crate::check::Expectation;
+use crate::Expectation;
 use rustc_ast as ast;
 use rustc_errors::{self, struct_span_err, Applicability, Diagnostic};
 use rustc_hir as hir;
diff --git a/compiler/rustc_hir_analysis/src/check/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 178326cfdc4..ea90da4a6dc 100644
--- a/compiler/rustc_hir_analysis/src/check/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -1,6 +1,5 @@
-use crate::check::FnCtxt;
+use crate::FnCtxt;
 use rustc_ast as ast;
-
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
diff --git a/compiler/rustc_hir_analysis/src/check/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index 2e0f37eba23..ba8cf6926f3 100644
--- a/compiler/rustc_hir_analysis/src/check/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -1,5 +1,5 @@
-use crate::check::method::MethodCallee;
-use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
+use crate::method::MethodCallee;
+use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp};
 use rustc_ast as ast;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
diff --git a/compiler/rustc_hir_analysis/src/check/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
index 22c9e796107..22c9e796107 100644
--- a/compiler/rustc_hir_analysis/src/check/rvalue_scopes.rs
+++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
diff --git a/compiler/rustc_hir_analysis/src/check/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 4f495641691..4dea40829f6 100644
--- a/compiler/rustc_hir_analysis/src/check/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -352,7 +352,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// and that the path can be captured with required capture kind (depending on use in closure,
     /// move closure etc.)
     ///
-    /// Returns the set of of adjusted information along with the inferred closure kind and span
+    /// Returns the set of adjusted information along with the inferred closure kind and span
     /// associated with the closure kind inference.
     ///
     /// Note that we *always* infer a minimal kind, even if
diff --git a/compiler/rustc_hir_analysis/src/check/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 3583769b7cd..1e26daa9c2c 100644
--- a/compiler/rustc_hir_analysis/src/check/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -2,7 +2,7 @@
 // unresolved type variables and replaces "ty_var" types with their
 // substitutions.
 
-use crate::check::FnCtxt;
+use crate::FnCtxt;
 use hir::def_id::LocalDefId;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
@@ -536,33 +536,37 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         let opaque_types =
             self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
         for (opaque_type_key, decl) in opaque_types {
-            let hidden_type = match decl.origin {
-                hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
-                    let ty = self.resolve(decl.hidden_type.ty, &decl.hidden_type.span);
-                    struct RecursionChecker {
-                        def_id: LocalDefId,
-                    }
-                    impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
-                        type BreakTy = ();
-                        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-                            if let ty::Opaque(def_id, _) = *t.kind() {
-                                if def_id == self.def_id.to_def_id() {
-                                    return ControlFlow::Break(());
-                                }
-                            }
-                            t.super_visit_with(self)
+            let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
+            let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);
+
+            struct RecursionChecker {
+                def_id: LocalDefId,
+            }
+            impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
+                type BreakTy = ();
+                fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+                    if let ty::Opaque(def_id, _) = *t.kind() {
+                        if def_id == self.def_id.to_def_id() {
+                            return ControlFlow::Break(());
                         }
                     }
-                    if ty
-                        .visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
-                        .is_break()
-                    {
-                        return;
-                    }
-                    Some(ty)
+                    t.super_visit_with(self)
                 }
-                hir::OpaqueTyOrigin::TyAlias => None,
-            };
+            }
+            if hidden_type
+                .visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
+                .is_break()
+            {
+                continue;
+            }
+
+            let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
+                opaque_type_key,
+                self.fcx.infcx.tcx,
+                true,
+                decl.origin,
+            );
+
             self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
         }
     }
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 9c19f16a496..79e2d371ed3 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -149,19 +149,19 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
         let crate_items = tcx.hir_crate_items(());
 
         for id in crate_items.items() {
-            dirty_clean_visitor.check_item(id.def_id.def_id);
+            dirty_clean_visitor.check_item(id.owner_id.def_id);
         }
 
         for id in crate_items.trait_items() {
-            dirty_clean_visitor.check_item(id.def_id.def_id);
+            dirty_clean_visitor.check_item(id.owner_id.def_id);
         }
 
         for id in crate_items.impl_items() {
-            dirty_clean_visitor.check_item(id.def_id.def_id);
+            dirty_clean_visitor.check_item(id.owner_id.def_id);
         }
 
         for id in crate_items.foreign_items() {
-            dirty_clean_visitor.check_item(id.def_id.def_id);
+            dirty_clean_visitor.check_item(id.owner_id.def_id);
         }
 
         let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] };
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 500900d3d4a..bb04e1c49ba 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -18,19 +18,19 @@ use crate::infer::error_reporting::{
 pub mod note_and_explain;
 
 #[derive(Diagnostic)]
-#[diag(infer::opaque_hidden_type)]
+#[diag(infer_opaque_hidden_type)]
 pub struct OpaqueHiddenTypeDiag {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[note(infer::opaque_type)]
+    #[note(opaque_type)]
     pub opaque_type: Span,
-    #[note(infer::hidden_type)]
+    #[note(hidden_type)]
     pub hidden_type: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0282")]
+#[diag(infer_type_annotations_needed, code = "E0282")]
 pub struct AnnotationRequired<'a> {
     #[primary_span]
     pub span: Span,
@@ -48,7 +48,7 @@ pub struct AnnotationRequired<'a> {
 
 // Copy of `AnnotationRequired` for E0283
 #[derive(Diagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0283")]
+#[diag(infer_type_annotations_needed, code = "E0283")]
 pub struct AmbigousImpl<'a> {
     #[primary_span]
     pub span: Span,
@@ -66,7 +66,7 @@ pub struct AmbigousImpl<'a> {
 
 // Copy of `AnnotationRequired` for E0284
 #[derive(Diagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0284")]
+#[diag(infer_type_annotations_needed, code = "E0284")]
 pub struct AmbigousReturn<'a> {
     #[primary_span]
     pub span: Span,
@@ -83,7 +83,7 @@ pub struct AmbigousReturn<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(infer::need_type_info_in_generator, code = "E0698")]
+#[diag(infer_need_type_info_in_generator, code = "E0698")]
 pub struct NeedTypeInfoInGenerator<'a> {
     #[primary_span]
     pub span: Span,
@@ -94,7 +94,7 @@ pub struct NeedTypeInfoInGenerator<'a> {
 
 // Used when a better one isn't available
 #[derive(Subdiagnostic)]
-#[label(infer::label_bad)]
+#[label(infer_label_bad)]
 pub struct InferenceBadError<'a> {
     #[primary_span]
     pub span: Span,
@@ -109,8 +109,9 @@ pub struct InferenceBadError<'a> {
 
 #[derive(Subdiagnostic)]
 pub enum SourceKindSubdiag<'a> {
-    #[suggestion_verbose(
-        infer::source_kind_subdiag_let,
+    #[suggestion(
+        infer_source_kind_subdiag_let,
+        style = "verbose",
         code = ": {type_name}",
         applicability = "has-placeholders"
     )]
@@ -125,7 +126,7 @@ pub enum SourceKindSubdiag<'a> {
         prefix: &'a str,
         arg_name: String,
     },
-    #[label(infer::source_kind_subdiag_generic_label)]
+    #[label(infer_source_kind_subdiag_generic_label)]
     GenericLabel {
         #[primary_span]
         span: Span,
@@ -135,8 +136,9 @@ pub enum SourceKindSubdiag<'a> {
         parent_prefix: String,
         parent_name: String,
     },
-    #[suggestion_verbose(
-        infer::source_kind_subdiag_generic_suggestion,
+    #[suggestion(
+        infer_source_kind_subdiag_generic_suggestion,
+        style = "verbose",
         code = "::<{args}>",
         applicability = "has-placeholders"
     )]
@@ -150,8 +152,9 @@ pub enum SourceKindSubdiag<'a> {
 
 #[derive(Subdiagnostic)]
 pub enum SourceKindMultiSuggestion<'a> {
-    #[multipart_suggestion_verbose(
-        infer::source_kind_fully_qualified,
+    #[multipart_suggestion(
+        infer_source_kind_fully_qualified,
+        style = "verbose",
         applicability = "has-placeholders"
     )]
     FullyQualified {
@@ -163,8 +166,9 @@ pub enum SourceKindMultiSuggestion<'a> {
         adjustment: &'a str,
         successor_pos: &'a str,
     },
-    #[multipart_suggestion_verbose(
-        infer::source_kind_closure_return,
+    #[multipart_suggestion(
+        infer_source_kind_closure_return,
+        style = "verbose",
         applicability = "has-placeholders"
     )]
     ClosureReturn {
@@ -260,7 +264,7 @@ impl AddToDiagnostic for RegionOriginNote<'_> {
                 requirement,
                 expected_found: Some((expected, found)),
             } => {
-                label_or_note(span, fluent::infer::subtype);
+                label_or_note(span, fluent::infer_subtype);
                 diag.set_arg("requirement", requirement);
 
                 diag.note_expected_found(&"", expected, &"", found);
@@ -269,7 +273,7 @@ impl AddToDiagnostic for RegionOriginNote<'_> {
                 // FIXME: this really should be handled at some earlier stage. Our
                 // handling of region checking when type errors are present is
                 // *terrible*.
-                label_or_note(span, fluent::infer::subtype_2);
+                label_or_note(span, fluent::infer_subtype_2);
                 diag.set_arg("requirement", requirement);
             }
         };
@@ -300,9 +304,9 @@ impl AddToDiagnostic for LifetimeMismatchLabels {
     {
         match self {
             LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
-                diag.span_label(param_span, fluent::infer::declared_different);
-                diag.span_label(ret_span, fluent::infer::nothing);
-                diag.span_label(span, fluent::infer::data_returned);
+                diag.span_label(param_span, fluent::infer_declared_different);
+                diag.span_label(ret_span, fluent::infer_nothing);
+                diag.span_label(span, fluent::infer_data_returned);
                 diag.set_arg("label_var1_exists", label_var1.is_some());
                 diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
             }
@@ -315,13 +319,13 @@ impl AddToDiagnostic for LifetimeMismatchLabels {
                 sub: label_var2,
             } => {
                 if hir_equal {
-                    diag.span_label(ty_sup, fluent::infer::declared_multiple);
-                    diag.span_label(ty_sub, fluent::infer::nothing);
-                    diag.span_label(span, fluent::infer::data_lifetime_flow);
+                    diag.span_label(ty_sup, fluent::infer_declared_multiple);
+                    diag.span_label(ty_sub, fluent::infer_nothing);
+                    diag.span_label(span, fluent::infer_data_lifetime_flow);
                 } else {
-                    diag.span_label(ty_sup, fluent::infer::types_declared_different);
-                    diag.span_label(ty_sub, fluent::infer::nothing);
-                    diag.span_label(span, fluent::infer::data_flows);
+                    diag.span_label(ty_sup, fluent::infer_types_declared_different);
+                    diag.span_label(ty_sub, fluent::infer_nothing);
+                    diag.span_label(span, fluent::infer_data_flows);
                     diag.set_arg("label_var1_exists", label_var1.is_some());
                     diag.set_arg(
                         "label_var1",
@@ -419,7 +423,7 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
             }
 
             diag.multipart_suggestion(
-                fluent::infer::lifetime_param_suggestion,
+                fluent::infer_lifetime_param_suggestion,
                 suggestions,
                 Applicability::MaybeIncorrect,
             );
@@ -427,13 +431,13 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
             true
         };
         if mk_suggestion() && self.add_note {
-            diag.note(fluent::infer::lifetime_param_suggestion_elided);
+            diag.note(fluent::infer_lifetime_param_suggestion_elided);
         }
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(infer::lifetime_mismatch, code = "E0623")]
+#[diag(infer_lifetime_mismatch, code = "E0623")]
 pub struct LifetimeMismatch<'a> {
     #[primary_span]
     pub span: Span,
@@ -454,56 +458,44 @@ impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
         F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
     {
         self.unmet_requirements
-            .push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
-        diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req);
+            .push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
+        diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req);
     }
 }
 
-pub struct ImplNote {
-    pub impl_span: Option<Span>,
-}
-
-impl AddToDiagnostic for ImplNote {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        match self.impl_span {
-            Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
-            None => diag.note(fluent::infer::msl_impl_note),
-        };
-    }
-}
-
-pub enum TraitSubdiag {
-    Note { span: Span },
-    Sugg { span: Span },
+// FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that
+#[derive(Subdiagnostic)]
+pub enum DoesNotOutliveStaticFromImpl {
+    #[note(infer_does_not_outlive_static_from_impl)]
+    Spanned {
+        #[primary_span]
+        span: Span,
+    },
+    #[note(infer_does_not_outlive_static_from_impl)]
+    Unspanned,
 }
 
-// FIXME(#100717) used in `Vec<TraitSubdiag>` so requires eager translation/list support
-impl AddToDiagnostic for TraitSubdiag {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        match self {
-            TraitSubdiag::Note { span } => {
-                diag.span_note(span, "this has an implicit `'static` lifetime requirement");
-            }
-            TraitSubdiag::Sugg { span } => {
-                diag.span_suggestion_verbose(
-                    span,
-                    "consider relaxing the implicit `'static` requirement",
-                    " + '_".to_owned(),
-                    rustc_errors::Applicability::MaybeIncorrect,
-                );
-            }
-        }
-    }
+#[derive(Subdiagnostic)]
+pub enum ImplicitStaticLifetimeSubdiag {
+    #[note(infer_implicit_static_lifetime_note)]
+    Note {
+        #[primary_span]
+        span: Span,
+    },
+    #[suggestion(
+        infer_implicit_static_lifetime_suggestion,
+        style = "verbose",
+        code = " + '_",
+        applicability = "maybe-incorrect"
+    )]
+    Sugg {
+        #[primary_span]
+        span: Span,
+    },
 }
 
 #[derive(Diagnostic)]
-#[diag(infer::mismatched_static_lifetime)]
+#[diag(infer_mismatched_static_lifetime)]
 pub struct MismatchedStaticLifetime<'a> {
     #[primary_span]
     pub cause_span: Span,
@@ -512,7 +504,7 @@ pub struct MismatchedStaticLifetime<'a> {
     #[subdiagnostic]
     pub expl: Option<note_and_explain::RegionExplanation<'a>>,
     #[subdiagnostic]
-    pub impl_note: ImplNote,
-    #[subdiagnostic]
-    pub trait_subdiags: Vec<TraitSubdiag>,
+    pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
+    #[subdiagnostic(eager)]
+    pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
 }
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index 201a3c7100c..6a29d85627a 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -166,9 +166,9 @@ impl AddToDiagnostic for RegionExplanation<'_> {
         F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
     {
         if let Some(span) = self.desc.span {
-            diag.span_note(span, fluent::infer::region_explanation);
+            diag.span_note(span, fluent::infer_region_explanation);
         } else {
-            diag.note(fluent::infer::region_explanation);
+            diag.note(fluent::infer_region_explanation);
         }
         self.desc.add_to(diag);
         diag.set_arg("pref_kind", self.prefix);
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 06ca2534d5c..cbd6481f9cb 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -43,7 +43,7 @@ impl<'tcx> InferCtxt<'tcx> {
     ///
     /// This is only meant to be invoked as part of constructing an
     /// inference context at the start of a query (see
-    /// `InferCtxtBuilder::enter_with_canonical`). It basically
+    /// `InferCtxtBuilder::build_with_canonical`). It basically
     /// brings the canonical value "into scope" within your new infcx.
     ///
     /// At the end of processing, the substitution S (once
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index eb0135d76f1..a299a3e578d 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -16,8 +16,8 @@ use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelating
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
 use crate::traits::query::{Fallible, NoSolution};
-use crate::traits::TraitEngine;
 use crate::traits::{Obligation, ObligationCause, PredicateObligation};
+use crate::traits::{PredicateObligations, TraitEngine};
 use rustc_data_structures::captures::Captures;
 use rustc_index::vec::Idx;
 use rustc_index::vec::IndexVec;
@@ -509,7 +509,7 @@ impl<'tcx> InferCtxt<'tcx> {
         for &(a, b) in &query_response.value.opaque_types {
             let a = substitute_value(self.tcx, &result_subst, a);
             let b = substitute_value(self.tcx, &result_subst, b);
-            obligations.extend(self.handle_opaque_type(a, b, true, cause, param_env)?.obligations);
+            obligations.extend(self.at(cause, param_env).eq(a, b)?.obligations);
         }
 
         Ok(InferOk { value: result_subst, obligations })
@@ -741,17 +741,11 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
         true
     }
 
-    fn register_opaque_type(
+    fn register_opaque_type_obligations(
         &mut self,
-        a: Ty<'tcx>,
-        b: Ty<'tcx>,
-        a_is_expected: bool,
+        obligations: PredicateObligations<'tcx>,
     ) -> Result<(), TypeError<'tcx>> {
-        self.obligations.extend(
-            self.infcx
-                .handle_opaque_type(a, b, a_is_expected, &self.cause, self.param_env)?
-                .obligations,
-        );
+        self.obligations.extend(obligations);
         Ok(())
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index ddeeaa9618e..9ff703e521f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -338,8 +338,7 @@ impl<'tcx> InferCtxt<'tcx> {
 
             let bounds = self.tcx.bound_explicit_item_bounds(*def_id);
 
-            for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
-                let predicate = predicate.subst(self.tcx, substs);
+            for (predicate, _) in bounds.subst_iter_copied(self.tcx, substs) {
                 let output = predicate
                     .kind()
                     .map_bound(|kind| match kind {
@@ -2272,6 +2271,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
             }
             FailureCode::Error0308(failure_str) => {
+                fn escape_literal(s: &str) -> String {
+                    let mut escaped = String::with_capacity(s.len());
+                    let mut chrs = s.chars().peekable();
+                    while let Some(first) = chrs.next() {
+                        match (first, chrs.peek()) {
+                            ('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => {
+                                escaped.push('\\');
+                                escaped.push(delim);
+                                chrs.next();
+                            }
+                            ('"' | '\'', _) => {
+                                escaped.push('\\');
+                                escaped.push(first)
+                            }
+                            (c, _) => escaped.push(c),
+                        };
+                    }
+                    escaped
+                }
                 let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
                 if let Some((expected, found)) = trace.values.ty() {
                     match (expected.kind(), found.kind()) {
@@ -2293,7 +2311,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 err.span_suggestion(
                                     span,
                                     "if you meant to write a `char` literal, use single quotes",
-                                    format!("'{}'", code),
+                                    format!("'{}'", escape_literal(code)),
                                     Applicability::MachineApplicable,
                                 );
                             }
@@ -2308,7 +2326,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                     err.span_suggestion(
                                         span,
                                         "if you meant to write a `str` literal, use double quotes",
-                                        format!("\"{}\"", code),
+                                        format!("\"{}\"", escape_literal(code)),
                                         Applicability::MachineApplicable,
                                     );
                                 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index f4b3ded53b0..7b3178e610f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -902,11 +902,18 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
             // impl is currently the `DefId` of `Output` in the trait definition
             // which makes this somewhat difficult and prevents us from just
             // using `self.path_inferred_subst_iter` here.
-            hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _) => {
-                if let Some(ty) = self.opt_node_type(expr.hir_id) {
-                    if let ty::Adt(_, substs) = ty.kind() {
-                        return Box::new(self.resolved_path_inferred_subst_iter(path, substs));
-                    }
+            hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _)
+            // FIXME(TaKO8Ki): Ideally we should support this. For that
+            // we have to map back from the self type to the
+            // type alias though. That's difficult.
+            //
+            // See the `need_type_info/issue-103053.rs` test for
+            // a example.
+            if !matches!(path.res, Res::Def(DefKind::TyAlias, _)) => {
+                if let Some(ty) = self.opt_node_type(expr.hir_id)
+                    && let ty::Adt(_, substs) = ty.kind()
+                {
+                    return Box::new(self.resolved_path_inferred_subst_iter(path, substs));
                 }
             }
             hir::ExprKind::MethodCall(segment, ..) => {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index 1410e2b63b0..c5f2a1a3f7d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -2,7 +2,9 @@
 //! to hold.
 
 use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq};
-use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag};
+use crate::errors::{
+    DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag, MismatchedStaticLifetime,
+};
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{SubregionOrigin, TypeTrace};
@@ -56,7 +58,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             note_and_explain::SuffixKind::Continues,
         );
         let mut impl_span = None;
-        let mut trait_subdiags = Vec::new();
+        let mut implicit_static_lifetimes = Vec::new();
         if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
             // If an impl is local, then maybe this isn't what they want. Try to
             // be as helpful as possible with implicit lifetimes.
@@ -90,10 +92,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 // Otherwise, point at all implicit static lifetimes
 
                 for span in &traits {
-                    trait_subdiags.push(TraitSubdiag::Note { span: *span });
+                    implicit_static_lifetimes
+                        .push(ImplicitStaticLifetimeSubdiag::Note { span: *span });
                     // It would be nice to put this immediately under the above note, but they get
                     // pushed to the end.
-                    trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() });
+                    implicit_static_lifetimes
+                        .push(ImplicitStaticLifetimeSubdiag::Sugg { span: span.shrink_to_hi() });
                 }
             }
         } else {
@@ -105,8 +109,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             cause_span: cause.span,
             unmet_lifetime_reqs: multispan_subdiag,
             expl,
-            impl_note: ImplNote { impl_span },
-            trait_subdiags,
+            does_not_outlive_static_from_impl: impl_span
+                .map(|span| DoesNotOutliveStaticFromImpl::Spanned { span })
+                .unwrap_or(DoesNotOutliveStaticFromImpl::Unspanned),
+            implicit_static_lifetimes,
         };
         let reported = self.tcx().sess.emit_err(err);
         Some(reported)
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 6bb736687d6..9bf755d7fcd 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -286,8 +286,8 @@ pub fn suggest_new_region_bound(
 ) {
     debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
     // FIXME: account for the need of parens in `&(dyn Trait + '_)`
-    let consider = "consider changing the";
-    let declare = "to declare that the";
+    let consider = "consider changing";
+    let declare = "to declare that";
     let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
     let explicit_static =
         arg.map(|arg| format!("explicit `'static` bound to the lifetime of {}", arg));
@@ -305,6 +305,10 @@ pub fn suggest_new_region_bound(
                     return;
                 };
 
+                // Get the identity type for this RPIT
+                let did = item_id.owner_id.to_def_id();
+                let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
+
                 if let Some(span) = opaque
                     .bounds
                     .iter()
@@ -321,7 +325,7 @@ pub fn suggest_new_region_bound(
                     if let Some(explicit_static) = &explicit_static {
                         err.span_suggestion_verbose(
                             span,
-                            &format!("{} `impl Trait`'s {}", consider, explicit_static),
+                            &format!("{consider} `{ty}`'s {explicit_static}"),
                             &lifetime_name,
                             Applicability::MaybeIncorrect,
                         );
@@ -351,12 +355,7 @@ pub fn suggest_new_region_bound(
                 } else {
                     err.span_suggestion_verbose(
                         fn_return.span.shrink_to_hi(),
-                        &format!(
-                            "{declare} `impl Trait` {captures}, {explicit}",
-                            declare = declare,
-                            captures = captures,
-                            explicit = explicit,
-                        ),
+                        &format!("{declare} `{ty}` {captures}, {explicit}",),
                         &plus_lt,
                         Applicability::MaybeIncorrect,
                     );
@@ -367,7 +366,7 @@ pub fn suggest_new_region_bound(
                     err.span_suggestion_verbose(
                         fn_return.span.shrink_to_hi(),
                         &format!(
-                            "{declare} trait object {captures}, {explicit}",
+                            "{declare} the trait object {captures}, {explicit}",
                             declare = declare,
                             captures = captures,
                             explicit = explicit,
@@ -384,7 +383,7 @@ pub fn suggest_new_region_bound(
                     if let Some(explicit_static) = &explicit_static {
                         err.span_suggestion_verbose(
                             lt.span,
-                            &format!("{} trait object's {}", consider, explicit_static),
+                            &format!("{} the trait object's {}", consider, explicit_static),
                             &lifetime_name,
                             Applicability::MaybeIncorrect,
                         );
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index a04245a23a2..41b115f3377 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -19,26 +19,27 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 expected_found: self.values_str(trace.values),
             }
             .add_to_diagnostic(err),
-            infer::Reborrow(span) => RegionOriginNote::Plain { span, msg: fluent::infer::reborrow }
-                .add_to_diagnostic(err),
+            infer::Reborrow(span) => {
+                RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
+            }
             infer::ReborrowUpvar(span, ref upvar_id) => {
                 let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
                 RegionOriginNote::WithName {
                     span,
-                    msg: fluent::infer::reborrow,
+                    msg: fluent::infer_reborrow,
                     name: &var_name.to_string(),
                     continues: false,
                 }
                 .add_to_diagnostic(err);
             }
             infer::RelateObjectBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer::relate_object_bound }
+                RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
                     .add_to_diagnostic(err);
             }
             infer::DataBorrowed(ty, span) => {
                 RegionOriginNote::WithName {
                     span,
-                    msg: fluent::infer::data_borrowed,
+                    msg: fluent::infer_data_borrowed,
                     name: &self.ty_to_string(ty),
                     continues: false,
                 }
@@ -47,7 +48,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::ReferenceOutlivesReferent(ty, span) => {
                 RegionOriginNote::WithName {
                     span,
-                    msg: fluent::infer::reference_outlives_referent,
+                    msg: fluent::infer_reference_outlives_referent,
                     name: &self.ty_to_string(ty),
                     continues: false,
                 }
@@ -56,22 +57,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::RelateParamBound(span, ty, opt_span) => {
                 RegionOriginNote::WithName {
                     span,
-                    msg: fluent::infer::relate_param_bound,
+                    msg: fluent::infer_relate_param_bound,
                     name: &self.ty_to_string(ty),
                     continues: opt_span.is_some(),
                 }
                 .add_to_diagnostic(err);
                 if let Some(span) = opt_span {
-                    RegionOriginNote::Plain { span, msg: fluent::infer::relate_param_bound_2 }
+                    RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
                         .add_to_diagnostic(err);
                 }
             }
             infer::RelateRegionParamBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer::relate_region_param_bound }
+                RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
                     .add_to_diagnostic(err);
             }
             infer::CompareImplItemObligation { span, .. } => {
-                RegionOriginNote::Plain { span, msg: fluent::infer::compare_impl_item_obligation }
+                RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
                     .add_to_diagnostic(err);
             }
             infer::CheckAssociatedTypeBounds { ref parent, .. } => {
@@ -80,7 +81,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::AscribeUserTypeProvePredicate(span) => {
                 RegionOriginNote::Plain {
                     span,
-                    msg: fluent::infer::ascribe_user_type_prove_predicate,
+                    msg: fluent::infer_ascribe_user_type_prove_predicate,
                 }
                 .add_to_diagnostic(err);
             }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 5a5e9db81a2..ffb020398b8 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1150,8 +1150,8 @@ impl<'tcx> InferCtxt<'tcx> {
     /// Return the universe that the region `r` was created in.  For
     /// most regions (e.g., `'static`, named regions from the user,
     /// etc) this is the root universe U0. For inference variables or
-    /// placeholders, however, it will return the universe which which
-    /// they are associated.
+    /// placeholders, however, it will return the universe which they
+    /// are associated.
     pub fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex {
         self.inner.borrow_mut().unwrap_region_constraints().universe(r)
     }
@@ -1469,7 +1469,12 @@ impl<'tcx> InferCtxt<'tcx> {
          * except during the writeback phase.
          */
 
-        resolve::fully_resolve(self, value)
+        let value = resolve::fully_resolve(self, value);
+        assert!(
+            value.as_ref().map_or(true, |value| !value.needs_infer()),
+            "`{value:?}` is not fully resolved"
+        );
+        value
     }
 
     pub fn replace_bound_vars_with_fresh_vars<T>(
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 7c186ae9470..600f94f095e 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -25,7 +25,9 @@ use crate::infer::combine::ConstEquateRelation;
 use crate::infer::InferCtxt;
 use crate::infer::{ConstVarValue, ConstVariableValue};
 use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::traits::PredicateObligation;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
@@ -91,11 +93,9 @@ pub trait TypeRelatingDelegate<'tcx> {
     );
 
     fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
-    fn register_opaque_type(
+    fn register_opaque_type_obligations(
         &mut self,
-        a: Ty<'tcx>,
-        b: Ty<'tcx>,
-        a_is_expected: bool,
+        obligations: Vec<PredicateObligation<'tcx>>,
     ) -> Result<(), TypeError<'tcx>>;
 
     /// Creates a new universe index. Used when instantiating placeholders.
@@ -414,7 +414,12 @@ where
             (_, &ty::Opaque(..)) => (generalize(a, true)?, b),
             _ => unreachable!(),
         };
-        self.delegate.register_opaque_type(a, b, true)?;
+        let cause = ObligationCause::dummy_with_span(self.delegate.span());
+        let obligations = self
+            .infcx
+            .handle_opaque_type(a, b, true, &cause, self.delegate.param_env())?
+            .obligations;
+        self.delegate.register_opaque_type_obligations(obligations)?;
         trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
         Ok(a)
     }
@@ -592,7 +597,7 @@ where
             (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
 
             (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
-                infcx.commit_if_ok(|_| infcx.super_combine_tys(self, a, b)).or_else(|err| {
+                infcx.super_combine_tys(self, a, b).or_else(|err| {
                     self.tcx().sess.delay_span_bug(
                         self.delegate.span(),
                         "failure to relate an opaque to itself should result in an error later on",
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 77e8f72aefa..a982f11f718 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,6 +1,7 @@
 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::{HirId, OpaqueTyOrigin};
 use rustc_data_structures::sync::Lrc;
@@ -102,7 +103,7 @@ impl<'tcx> InferCtxt<'tcx> {
             return Ok(InferOk { value: (), obligations: vec![] });
         }
         let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
-        let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
+        let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
             ty::Opaque(def_id, substs) if def_id.is_local() => {
                 let def_id = def_id.expect_local();
                 let origin = match self.defining_use_anchor {
@@ -168,13 +169,14 @@ impl<'tcx> InferCtxt<'tcx> {
                     param_env,
                     b,
                     origin,
+                    a_is_expected,
                 ))
             }
             _ => None,
         };
-        if let Some(res) = process(a, b) {
+        if let Some(res) = process(a, b, true) {
             res
-        } else if let Some(res) = process(b, a) {
+        } else if let Some(res) = process(b, a, false) {
             res
         } else {
             let (a, b) = self.resolve_vars_if_possible((a, b));
@@ -513,13 +515,14 @@ impl UseKind {
 
 impl<'tcx> InferCtxt<'tcx> {
     #[instrument(skip(self), level = "debug")]
-    pub fn register_hidden_type(
+    fn register_hidden_type(
         &self,
         opaque_type_key: OpaqueTypeKey<'tcx>,
         cause: ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         hidden_ty: Ty<'tcx>,
         origin: hir::OpaqueTyOrigin,
+        a_is_expected: bool,
     ) -> InferResult<'tcx, ()> {
         let tcx = self.tcx;
         let OpaqueTypeKey { def_id, substs } = opaque_type_key;
@@ -538,21 +541,24 @@ impl<'tcx> InferCtxt<'tcx> {
             origin,
         );
         if let Some(prev) = prev {
-            obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations;
+            obligations =
+                self.at(&cause, param_env).eq_exp(a_is_expected, prev, hidden_ty)?.obligations;
         }
 
         let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id());
 
-        for predicate in item_bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
-            debug!(?predicate);
-            let predicate = predicate.subst(tcx, substs);
-
+        for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) {
             let predicate = predicate.fold_with(&mut BottomUpFolder {
                 tcx,
                 ty_op: |ty| match *ty.kind() {
                     // We can't normalize associated types from `rustc_infer`,
                     // but we can eagerly register inference variables for them.
-                    ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => {
+                    // FIXME(RPITIT): Don't replace RPITITs with inference vars.
+                    ty::Projection(projection_ty)
+                        if !projection_ty.has_escaping_bound_vars()
+                            && tcx.def_kind(projection_ty.item_def_id)
+                                != DefKind::ImplTraitPlaceholder =>
+                    {
                         self.infer_projection(
                             param_env,
                             projection_ty,
@@ -568,6 +574,12 @@ impl<'tcx> InferCtxt<'tcx> {
                     {
                         hidden_ty
                     }
+                    // FIXME(RPITIT): This can go away when we move to associated types
+                    ty::Projection(proj)
+                        if def_id.to_def_id() == proj.item_def_id && substs == proj.substs =>
+                    {
+                        hidden_ty
+                    }
                     _ => ty,
                 },
                 lt_op: |lt| lt,
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 069f9600091..4db4ff2388d 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,6 +1,5 @@
 use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use super::{FixupError, FixupResult, InferCtxt, Span};
-use rustc_middle::mir;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor};
 use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable};
@@ -48,10 +47,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
             ct.super_fold_with(self)
         }
     }
-
-    fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
-        constant.super_fold_with(self)
-    }
 }
 
 /// The opportunistic region resolver opportunistically resolves regions
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index a4b55dfa691..97354ba5d1b 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -2,9 +2,7 @@ use super::combine::{CombineFields, RelationDir};
 use super::SubregionOrigin;
 
 use crate::infer::combine::ConstEquateRelation;
-use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::traits::Obligation;
-use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::TyVar;
@@ -130,39 +128,18 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
             (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
                 if self.fields.define_opaque_types && did.is_local() =>
             {
-                let mut generalize = |ty, ty_is_expected| {
-                    let var = infcx.next_ty_var_id_in_universe(
-                        TypeVariableOrigin {
-                            kind: TypeVariableOriginKind::MiscVariable,
-                            span: self.fields.trace.cause.span,
-                        },
-                        ty::UniverseIndex::ROOT,
-                    );
-                    self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?;
-                    Ok(infcx.tcx.mk_ty_var(var))
-                };
-                let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) };
-                let (ga, gb) = match (a.kind(), b.kind()) {
-                    (&ty::Opaque(..), _) => (a, generalize(b, true)?),
-                    (_, &ty::Opaque(..)) => (generalize(a, false)?, b),
-                    _ => unreachable!(),
-                };
                 self.fields.obligations.extend(
                     infcx
-                        .handle_opaque_type(ga, gb, true, &self.fields.trace.cause, self.param_env())
-                        // Don't leak any generalized type variables out of this
-                        // subtyping relation in the case of a type error.
-                        .map_err(|err| {
-                            let (ga, gb) = self.fields.infcx.resolve_vars_if_possible((ga, gb));
-                            if let TypeError::Sorts(sorts) = err && sorts.expected == ga && sorts.found == gb {
-                                TypeError::Sorts(ExpectedFound { expected: a, found: b })
-                            } else {
-                                err
-                            }
-                        })?
+                        .handle_opaque_type(
+                            a,
+                            b,
+                            self.a_is_expected,
+                            &self.fields.trace.cause,
+                            self.param_env(),
+                        )?
                         .obligations,
                 );
-                Ok(ga)
+                Ok(a)
             }
             // Optimization of GeneratorWitness relation since we know that all
             // free regions are replaced with bound regions during construction.
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index f0cb861c782..6a4c5b4d373 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -38,6 +38,7 @@ rustc_mir_transform = { path = "../rustc_mir_transform" }
 rustc_monomorphize = { path = "../rustc_monomorphize" }
 rustc_passes = { path = "../rustc_passes" }
 rustc_hir_analysis = { path = "../rustc_hir_analysis" }
+rustc_hir_typeck = { path = "../rustc_hir_typeck" }
 rustc_lint = { path = "../rustc_lint" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_plugin_impl = { path = "../rustc_plugin_impl" }
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index 097640f26c1..f5135c78dc8 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -5,7 +5,7 @@ use std::io;
 use std::path::Path;
 
 #[derive(Diagnostic)]
-#[diag(interface::ferris_identifier)]
+#[diag(interface_ferris_identifier)]
 pub struct FerrisIdentifier {
     #[primary_span]
     pub spans: Vec<Span>,
@@ -14,7 +14,7 @@ pub struct FerrisIdentifier {
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::emoji_identifier)]
+#[diag(interface_emoji_identifier)]
 pub struct EmojiIdentifier {
     #[primary_span]
     pub spans: Vec<Span>,
@@ -22,67 +22,67 @@ pub struct EmojiIdentifier {
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::mixed_bin_crate)]
+#[diag(interface_mixed_bin_crate)]
 pub struct MixedBinCrate;
 
 #[derive(Diagnostic)]
-#[diag(interface::mixed_proc_macro_crate)]
+#[diag(interface_mixed_proc_macro_crate)]
 pub struct MixedProcMacroCrate;
 
 #[derive(Diagnostic)]
-#[diag(interface::proc_macro_doc_without_arg)]
+#[diag(interface_proc_macro_doc_without_arg)]
 pub struct ProcMacroDocWithoutArg;
 
 #[derive(Diagnostic)]
-#[diag(interface::error_writing_dependencies)]
+#[diag(interface_error_writing_dependencies)]
 pub struct ErrorWritingDependencies<'a> {
     pub path: &'a Path,
     pub error: io::Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::input_file_would_be_overwritten)]
+#[diag(interface_input_file_would_be_overwritten)]
 pub struct InputFileWouldBeOverWritten<'a> {
     pub path: &'a Path,
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::generated_file_conflicts_with_directory)]
+#[diag(interface_generated_file_conflicts_with_directory)]
 pub struct GeneratedFileConflictsWithDirectory<'a> {
     pub input_path: &'a Path,
     pub dir_path: &'a Path,
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::temps_dir_error)]
+#[diag(interface_temps_dir_error)]
 pub struct TempsDirError;
 
 #[derive(Diagnostic)]
-#[diag(interface::out_dir_error)]
+#[diag(interface_out_dir_error)]
 pub struct OutDirError;
 
 #[derive(Diagnostic)]
-#[diag(interface::cant_emit_mir)]
+#[diag(interface_cant_emit_mir)]
 pub struct CantEmitMIR {
     pub error: io::Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::rustc_error_fatal)]
+#[diag(interface_rustc_error_fatal)]
 pub struct RustcErrorFatal {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::rustc_error_unexpected_annotation)]
+#[diag(interface_rustc_error_unexpected_annotation)]
 pub struct RustcErrorUnexpectedAnnotation {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::failed_writing_file)]
+#[diag(interface_failed_writing_file)]
 pub struct FailedWritingFile<'a> {
     pub path: &'a Path,
     pub error: io::Error,
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 949bd02ad68..89aaa0b95e4 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -17,7 +17,7 @@ use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilena
 use rustc_session::early_error;
 use rustc_session::lint;
 use rustc_session::parse::{CrateConfig, ParseSess};
-use rustc_session::{DiagnosticOutput, Session};
+use rustc_session::Session;
 use rustc_span::source_map::{FileLoader, FileName};
 use rustc_span::symbol::sym;
 use std::path::PathBuf;
@@ -25,7 +25,10 @@ use std::result;
 
 pub type Result<T> = result::Result<T, ErrorGuaranteed>;
 
-/// Represents a compiler session.
+/// Represents a compiler session. Note that every `Compiler` contains a
+/// `Session`, but `Compiler` also contains some things that cannot be in
+/// `Session`, due to `Session` being in a crate that has many fewer
+/// dependencies than this crate.
 ///
 /// Can be used to run `rustc_interface` queries.
 /// Created by passing [`Config`] to [`run_compiler`].
@@ -247,7 +250,6 @@ pub struct Config {
     pub output_dir: Option<PathBuf>,
     pub output_file: Option<PathBuf>,
     pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    pub diagnostic_output: DiagnosticOutput,
 
     pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
 
@@ -276,59 +278,6 @@ pub struct Config {
     pub registry: Registry,
 }
 
-pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R) -> R {
-    crate::callbacks::setup_callbacks();
-
-    let registry = &config.registry;
-    let (mut sess, codegen_backend) = util::create_session(
-        config.opts,
-        config.crate_cfg,
-        config.crate_check_cfg,
-        config.diagnostic_output,
-        config.file_loader,
-        config.input_path.clone(),
-        config.lint_caps,
-        config.make_codegen_backend,
-        registry.clone(),
-    );
-
-    if let Some(parse_sess_created) = config.parse_sess_created {
-        parse_sess_created(
-            &mut Lrc::get_mut(&mut sess)
-                .expect("create_session() should never share the returned session")
-                .parse_sess,
-        );
-    }
-
-    let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
-
-    let compiler = Compiler {
-        sess,
-        codegen_backend,
-        input: config.input,
-        input_path: config.input_path,
-        output_dir: config.output_dir,
-        output_file: config.output_file,
-        temps_dir,
-        register_lints: config.register_lints,
-        override_queries: config.override_queries,
-    };
-
-    rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
-        let r = {
-            let _sess_abort_error = OnDrop(|| {
-                compiler.sess.finish_diagnostics(registry);
-            });
-
-            f(&compiler)
-        };
-
-        let prof = compiler.sess.prof.clone();
-        prof.generic_activity("drop_compiler").run(move || drop(compiler));
-        r
-    })
-}
-
 // JUSTIFICATION: before session exists, only config
 #[allow(rustc::bad_opt_access)]
 pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
@@ -336,7 +285,53 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
     util::run_in_thread_pool_with_globals(
         config.opts.edition,
         config.opts.unstable_opts.threads,
-        || create_compiler_and_run(config, f),
+        || {
+            crate::callbacks::setup_callbacks();
+
+            let registry = &config.registry;
+            let (mut sess, codegen_backend) = util::create_session(
+                config.opts,
+                config.crate_cfg,
+                config.crate_check_cfg,
+                config.file_loader,
+                config.input_path.clone(),
+                config.lint_caps,
+                config.make_codegen_backend,
+                registry.clone(),
+            );
+
+            if let Some(parse_sess_created) = config.parse_sess_created {
+                parse_sess_created(&mut sess.parse_sess);
+            }
+
+            let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
+
+            let compiler = Compiler {
+                sess: Lrc::new(sess),
+                codegen_backend: Lrc::new(codegen_backend),
+                input: config.input,
+                input_path: config.input_path,
+                output_dir: config.output_dir,
+                output_file: config.output_file,
+                temps_dir,
+                register_lints: config.register_lints,
+                override_queries: config.override_queries,
+            };
+
+            rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
+                let r = {
+                    let _sess_abort_error = OnDrop(|| {
+                        compiler.sess.finish_diagnostics(registry);
+                    });
+
+                    f(&compiler)
+                };
+
+                let prof = compiler.sess.prof.clone();
+                prof.generic_activity("drop_compiler").run(move || drop(compiler));
+                r
+            })
+        },
     )
 }
 
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 8fd4224ca38..7f1d21bf1d8 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -16,7 +16,6 @@ use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_errors::{ErrorGuaranteed, PResult};
 use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
 use rustc_hir::def_id::StableCrateId;
-use rustc_hir::definitions::Definitions;
 use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore};
 use rustc_metadata::creader::CStore;
 use rustc_middle::arena::Arena;
@@ -30,7 +29,7 @@ use rustc_plugin_impl as plugin;
 use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
 use rustc_resolve::{Resolver, ResolverArenas};
 use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
-use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn};
+use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn};
 use rustc_session::output::filename_for_input;
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
@@ -135,10 +134,7 @@ mod boxed_resolver {
             f((&mut *resolver).as_mut().unwrap())
         }
 
-        pub fn to_resolver_outputs(
-            resolver: Rc<RefCell<BoxedResolver>>,
-        ) -> (Definitions, Box<CrateStoreDyn>, ty::ResolverOutputs, ty::ResolverAstLowering)
-        {
+        pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ty::ResolverOutputs {
             match Rc::try_unwrap(resolver) {
                 Ok(resolver) => {
                     let mut resolver = resolver.into_inner();
@@ -736,6 +732,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
     rustc_monomorphize::provide(providers);
     rustc_privacy::provide(providers);
     rustc_hir_analysis::provide(providers);
+    rustc_hir_typeck::provide(providers);
     ty::provide(providers);
     traits::provide(providers);
     rustc_passes::provide(providers);
@@ -787,8 +784,7 @@ pub fn create_global_ctxt<'tcx>(
     // incr. comp. yet.
     dep_graph.assert_ignored();
 
-    let (definitions, cstore, resolver_outputs, resolver_for_lowering) =
-        BoxedResolver::to_resolver_outputs(resolver);
+    let resolver_outputs = BoxedResolver::to_resolver_outputs(resolver);
 
     let sess = &compiler.session();
     let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
@@ -815,10 +811,7 @@ pub fn create_global_ctxt<'tcx>(
                 lint_store,
                 arena,
                 hir_arena,
-                definitions,
-                cstore,
                 resolver_outputs,
-                resolver_for_lowering,
                 krate,
                 dep_graph,
                 queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
@@ -934,7 +927,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
     sess.time("misc_checking_3", || {
         parallel!(
             {
-                tcx.ensure().privacy_access_levels(());
+                tcx.ensure().effective_visibilities(());
 
                 parallel!(
                     {
diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs
index 2b1b931b732..4c236c693d0 100644
--- a/compiler/rustc_interface/src/proc_macro_decls.rs
+++ b/compiler/rustc_interface/src/proc_macro_decls.rs
@@ -9,7 +9,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
     for id in tcx.hir().items() {
         let attrs = finder.tcx.hir().attrs(id.hir_id());
         if finder.tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) {
-            finder.decls = Some(id.def_id.def_id);
+            finder.decls = Some(id.owner_id.def_id);
         }
     }
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index d64cdcdbaa9..a03e7b0dae5 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -17,7 +17,7 @@ use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, Switc
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
 use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
-use rustc_session::{build_session, getopts, DiagnosticOutput, Session};
+use rustc_session::{build_session, getopts, Session};
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
 use rustc_span::SourceFileHashAlgorithm;
@@ -40,16 +40,7 @@ fn build_session_options_and_crate_config(matches: getopts::Matches) -> (Options
 fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
     let registry = registry::Registry::new(&[]);
     let (sessopts, cfg) = build_session_options_and_crate_config(matches);
-    let sess = build_session(
-        sessopts,
-        None,
-        None,
-        registry,
-        DiagnosticOutput::Default,
-        Default::default(),
-        None,
-        None,
-    );
+    let sess = build_session(sessopts, None, None, registry, Default::default(), None, None);
     (sess, cfg)
 }
 
@@ -657,6 +648,7 @@ fn test_unstable_options_tracking_hash() {
     untracked!(dump_mir_dir, String::from("abc"));
     untracked!(dump_mir_exclude_pass_number, true);
     untracked!(dump_mir_graphviz, true);
+    untracked!(dylib_lto, true);
     untracked!(emit_stack_sizes, true);
     untracked!(future_incompat_test, true);
     untracked!(hir_stats, true);
@@ -698,6 +690,7 @@ fn test_unstable_options_tracking_hash() {
     untracked!(time_llvm_passes, true);
     untracked!(time_passes, true);
     untracked!(trace_macros, true);
+    untracked!(track_diagnostics, true);
     untracked!(trim_diagnostic_paths, false);
     untracked!(ui_testing, true);
     untracked!(unpretty, Some("expanded".to_string()));
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index f7e70d355cf..519b8a7fc7c 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -3,22 +3,15 @@ use libloading::Library;
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-#[cfg(parallel_compiler)]
-use rustc_data_structures::jobserver;
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::registry::Registry;
-#[cfg(parallel_compiler)]
-use rustc_middle::ty::tls;
 use rustc_parse::validate_attr;
-#[cfg(parallel_compiler)]
-use rustc_query_impl::{QueryContext, QueryCtxt};
 use rustc_session as session;
 use rustc_session::config::CheckCfg;
 use rustc_session::config::{self, CrateType};
 use rustc_session::config::{ErrorOutputType, Input, OutputFilenames};
 use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::parse::CrateConfig;
-use rustc_session::{early_error, filesearch, output, DiagnosticOutput, Session};
+use rustc_session::{early_error, filesearch, output, Session};
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::FileLoader;
@@ -26,8 +19,6 @@ use rustc_span::symbol::{sym, Symbol};
 use std::env;
 use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
 use std::mem;
-#[cfg(not(parallel_compiler))]
-use std::panic;
 use std::path::{Path, PathBuf};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::OnceLock;
@@ -65,7 +56,6 @@ pub fn create_session(
     sopts: config::Options,
     cfg: FxHashSet<(String, Option<String>)>,
     check_cfg: CheckCfg,
-    diagnostic_output: DiagnosticOutput,
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
     input_path: Option<PathBuf>,
     lint_caps: FxHashMap<lint::LintId, lint::Level>,
@@ -73,7 +63,7 @@ pub fn create_session(
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
     >,
     descriptions: Registry,
-) -> (Lrc<Session>, Lrc<Box<dyn CodegenBackend>>) {
+) -> (Session, Box<dyn CodegenBackend>) {
     let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
         make_codegen_backend(&sopts)
     } else {
@@ -104,7 +94,6 @@ pub fn create_session(
         input_path,
         bundle,
         descriptions,
-        diagnostic_output,
         lint_caps,
         file_loader,
         target_override,
@@ -121,7 +110,7 @@ pub fn create_session(
     sess.parse_sess.config = cfg;
     sess.parse_sess.check_config = check_cfg;
 
-    (Lrc::new(sess), Lrc::new(codegen_backend))
+    (sess, codegen_backend)
 }
 
 const STACK_SIZE: usize = 8 * 1024 * 1024;
@@ -132,79 +121,86 @@ fn get_stack_size() -> Option<usize> {
     env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE)
 }
 
-/// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need
-/// for `'static` bounds.
-#[cfg(not(parallel_compiler))]
-fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
-    // SAFETY: join() is called immediately, so any closure captures are still
-    // alive.
-    match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() {
-        Ok(v) => v,
-        Err(e) => panic::resume_unwind(e),
-    }
-}
-
 #[cfg(not(parallel_compiler))]
-pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
+pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     edition: Edition,
     _threads: usize,
     f: F,
 ) -> R {
-    let mut cfg = thread::Builder::new().name("rustc".to_string());
-
+    // The "thread pool" is a single spawned thread in the non-parallel
+    // compiler. We run on a spawned thread instead of the main thread (a) to
+    // provide control over the stack size, and (b) to increase similarity with
+    // the parallel compiler, in particular to ensure there is no accidental
+    // sharing of data between the main thread and the compilation thread
+    // (which might cause problems for the parallel compiler).
+    let mut builder = thread::Builder::new().name("rustc".to_string());
     if let Some(size) = get_stack_size() {
-        cfg = cfg.stack_size(size);
+        builder = builder.stack_size(size);
     }
 
-    let main_handler = move || rustc_span::create_session_globals_then(edition, f);
-
-    scoped_thread(cfg, main_handler)
-}
-
-/// Creates a new thread and forwards information in thread locals to it.
-/// The new thread runs the deadlock handler.
-/// Must only be called when a deadlock is about to happen.
-#[cfg(parallel_compiler)]
-unsafe fn handle_deadlock() {
-    let registry = rustc_rayon_core::Registry::current();
-
-    let query_map = tls::with(|tcx| {
-        QueryCtxt::from_tcx(tcx)
-            .try_collect_active_jobs()
-            .expect("active jobs shouldn't be locked in deadlock handler")
-    });
-    thread::spawn(move || rustc_query_impl::deadlock(query_map, &registry));
+    // We build the session globals and run `f` on the spawned thread, because
+    // `SessionGlobals` does not impl `Send` in the non-parallel compiler.
+    thread::scope(|s| {
+        // `unwrap` is ok here because `spawn_scoped` only panics if the thread
+        // name contains null bytes.
+        let r = builder
+            .spawn_scoped(s, move || rustc_span::create_session_globals_then(edition, f))
+            .unwrap()
+            .join();
+
+        match r {
+            Ok(v) => v,
+            Err(e) => std::panic::resume_unwind(e),
+        }
+    })
 }
 
 #[cfg(parallel_compiler)]
-pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
+pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     edition: Edition,
     threads: usize,
     f: F,
 ) -> R {
-    let mut config = rayon::ThreadPoolBuilder::new()
+    use rustc_data_structures::jobserver;
+    use rustc_middle::ty::tls;
+    use rustc_query_impl::{deadlock, QueryContext, QueryCtxt};
+
+    let mut builder = rayon::ThreadPoolBuilder::new()
         .thread_name(|_| "rustc".to_string())
         .acquire_thread_handler(jobserver::acquire_thread)
         .release_thread_handler(jobserver::release_thread)
         .num_threads(threads)
-        .deadlock_handler(|| unsafe { handle_deadlock() });
-
+        .deadlock_handler(|| {
+            // On deadlock, creates a new thread and forwards information in thread
+            // locals to it. The new thread runs the deadlock handler.
+            let query_map = tls::with(|tcx| {
+                QueryCtxt::from_tcx(tcx)
+                    .try_collect_active_jobs()
+                    .expect("active jobs shouldn't be locked in deadlock handler")
+            });
+            let registry = rustc_rayon_core::Registry::current();
+            thread::spawn(move || deadlock(query_map, &registry));
+        });
     if let Some(size) = get_stack_size() {
-        config = config.stack_size(size);
+        builder = builder.stack_size(size);
     }
 
-    let with_pool = move |pool: &rayon::ThreadPool| pool.install(f);
-
+    // We create the session globals on the main thread, then create the thread
+    // pool. Upon creation, each worker thread created gets a copy of the
+    // session globals in TLS. This is possible because `SessionGlobals` impls
+    // `Send` in the parallel compiler.
     rustc_span::create_session_globals_then(edition, || {
         rustc_span::with_session_globals(|session_globals| {
-            // The main handler runs for each Rayon worker thread and sets up
-            // the thread local rustc uses. `session_globals` is captured and set
-            // on the new threads.
-            let main_handler = move |thread: rayon::ThreadBuilder| {
-                rustc_span::set_session_globals_then(session_globals, || thread.run())
-            };
-
-            config.build_scoped(main_handler, with_pool).unwrap()
+            builder
+                .build_scoped(
+                    // Initialize each new worker thread when created.
+                    move |thread: rayon::ThreadBuilder| {
+                        rustc_span::set_session_globals_then(session_globals, || thread.run())
+                    },
+                    // Run `f` on the first thread in the thread pool.
+                    move |pool: &rayon::ThreadPool| pool.install(f),
+                )
+                .unwrap()
         })
     })
 }
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index c71e6ffe34d..51515976e4e 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -57,29 +57,42 @@ pub enum TokenKind {
     // Multi-char tokens:
     /// "// comment"
     LineComment { doc_style: Option<DocStyle> },
+
     /// `/* block comment */`
     ///
-    /// Block comments can be recursive, so the sequence like `/* /* */`
+    /// Block comments can be recursive, so a sequence like `/* /* */`
     /// will not be considered terminated and will result in a parsing error.
     BlockComment { doc_style: Option<DocStyle>, terminated: bool },
-    /// Any whitespace characters sequence.
+
+    /// Any whitespace character sequence.
     Whitespace,
+
     /// "ident" or "continue"
-    /// At this step keywords are also considered identifiers.
+    ///
+    /// At this step, keywords are also considered identifiers.
     Ident,
+
     /// Like the above, but containing invalid unicode codepoints.
     InvalidIdent,
+
     /// "r#ident"
     RawIdent,
-    /// An unknown prefix like `foo#`, `foo'`, `foo"`. Note that only the
+
+    /// An unknown prefix, like `foo#`, `foo'`, `foo"`.
+    ///
+    /// Note that only the
     /// prefix (`foo`) is included in the token, not the separator (which is
     /// lexed as its own distinct token). In Rust 2021 and later, reserved
     /// prefixes are reported as errors; in earlier editions, they result in a
     /// (allowed by default) lint, and are treated as regular identifier
     /// tokens.
     UnknownPrefix,
-    /// "12_u8", "1.0e-40", "b"123"". See `LiteralKind` for more details.
+
+    /// Examples: `"12_u8"`, `"1.0e-40"`, `b"123`.
+    ///
+    /// See [LiteralKind] for more details.
     Literal { kind: LiteralKind, suffix_start: u32 },
+
     /// "'a"
     Lifetime { starts_with_number: bool },
 
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index bd6b637f76f..abebc533cc1 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -121,25 +121,25 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
             cx.struct_span_lint(
                 ARRAY_INTO_ITER,
                 call.ident.span,
-                fluent::lint::array_into_iter,
+                fluent::lint_array_into_iter,
                 |diag| {
                     diag.set_arg("target", target);
                     diag.span_suggestion(
                         call.ident.span,
-                        fluent::lint::use_iter_suggestion,
+                        fluent::use_iter_suggestion,
                         "iter",
                         Applicability::MachineApplicable,
                     );
                     if self.for_expr_span == expr.span {
                         diag.span_suggestion(
                             receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
-                            fluent::lint::remove_into_iter_suggestion,
+                            fluent::remove_into_iter_suggestion,
                             "",
                             Applicability::MaybeIncorrect,
                         );
                     } else if receiver_ty.is_array() {
                         diag.multipart_suggestion(
-                            fluent::lint::use_explicit_into_iter_suggestion,
+                            fluent::use_explicit_into_iter_suggestion,
                             vec![
                                 (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
                                 (
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index f28cfbd8b4c..27c04d82811 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -40,7 +40,7 @@ use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, Gate
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
-use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind, PredicateOrigin};
+use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin};
 use rustc_index::vec::Idx;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf};
@@ -106,11 +106,11 @@ impl EarlyLintPass for WhileTrue {
             cx.struct_span_lint(
                             WHILE_TRUE,
                             condition_span,
-                fluent::lint::builtin_while_true,
+                fluent::lint_builtin_while_true,
                             |lint| {
                     lint.span_suggestion_short(
                         condition_span,
-                        fluent::lint::suggestion,
+                        fluent::suggestion,
                         format!(
                             "{}loop",
                             label.map_or_else(String::new, |label| format!(
@@ -160,7 +160,7 @@ impl BoxPointers {
                     cx.struct_span_lint(
                         BOX_POINTERS,
                         span,
-                        fluent::lint::builtin_box_pointers,
+                        fluent::lint_builtin_box_pointers,
                         |lint| lint.set_arg("ty", ty),
                     );
                 }
@@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers {
             | hir::ItemKind::Enum(..)
             | hir::ItemKind::Struct(..)
             | hir::ItemKind::Union(..) => {
-                self.check_heap_type(cx, it.span, cx.tcx.type_of(it.def_id))
+                self.check_heap_type(cx, it.span, cx.tcx.type_of(it.owner_id))
             }
             _ => (),
         }
@@ -264,13 +264,13 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
                         cx.struct_span_lint(
                             NON_SHORTHAND_FIELD_PATTERNS,
                             fieldpat.span,
-                            fluent::lint::builtin_non_shorthand_field_patterns,
+                            fluent::lint_builtin_non_shorthand_field_patterns,
                             |lint| {
                                 let suggested_ident =
                                     format!("{}{}", binding_annot.prefix_str(), ident);
                                 lint.set_arg("ident", ident.clone()).span_suggestion(
                                     fieldpat.span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     suggested_ident,
                                     Applicability::MachineApplicable,
                                 )
@@ -335,7 +335,7 @@ impl UnsafeCode {
         msg: DiagnosticMessage,
     ) {
         self.report_unsafe(cx, span, msg, |lint| {
-            lint.note(fluent::lint::builtin_overridden_symbol_name)
+            lint.note(fluent::lint_builtin_overridden_symbol_name)
         })
     }
 
@@ -346,7 +346,7 @@ impl UnsafeCode {
         msg: DiagnosticMessage,
     ) {
         self.report_unsafe(cx, span, msg, |lint| {
-            lint.note(fluent::lint::builtin_overridden_symbol_section)
+            lint.note(fluent::lint_builtin_overridden_symbol_section)
         })
     }
 }
@@ -354,12 +354,9 @@ impl UnsafeCode {
 impl EarlyLintPass for UnsafeCode {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
         if attr.has_name(sym::allow_internal_unsafe) {
-            self.report_unsafe(
-                cx,
-                attr.span,
-                fluent::lint::builtin_allow_internal_unsafe,
-                |lint| lint,
-            );
+            self.report_unsafe(cx, attr.span, fluent::lint_builtin_allow_internal_unsafe, |lint| {
+                lint
+            });
         }
     }
 
@@ -367,7 +364,7 @@ impl EarlyLintPass for UnsafeCode {
         if let ast::ExprKind::Block(ref blk, _) = e.kind {
             // Don't warn about generated blocks; that'll just pollute the output.
             if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
-                self.report_unsafe(cx, blk.span, fluent::lint::builtin_unsafe_block, |lint| lint);
+                self.report_unsafe(cx, blk.span, fluent::lint_builtin_unsafe_block, |lint| lint);
             }
         }
     }
@@ -375,11 +372,11 @@ impl EarlyLintPass for UnsafeCode {
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         match it.kind {
             ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => {
-                self.report_unsafe(cx, it.span, fluent::lint::builtin_unsafe_trait, |lint| lint)
+                self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_trait, |lint| lint)
             }
 
             ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => {
-                self.report_unsafe(cx, it.span, fluent::lint::builtin_unsafe_impl, |lint| lint)
+                self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_impl, |lint| lint)
             }
 
             ast::ItemKind::Fn(..) => {
@@ -387,7 +384,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_name(
                         cx,
                         attr.span,
-                        fluent::lint::builtin_no_mangle_fn,
+                        fluent::lint_builtin_no_mangle_fn,
                     );
                 }
 
@@ -395,7 +392,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_name(
                         cx,
                         attr.span,
-                        fluent::lint::builtin_export_name_fn,
+                        fluent::lint_builtin_export_name_fn,
                     );
                 }
 
@@ -403,7 +400,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_section(
                         cx,
                         attr.span,
-                        fluent::lint::builtin_link_section_fn,
+                        fluent::lint_builtin_link_section_fn,
                     );
                 }
             }
@@ -413,7 +410,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_name(
                         cx,
                         attr.span,
-                        fluent::lint::builtin_no_mangle_static,
+                        fluent::lint_builtin_no_mangle_static,
                     );
                 }
 
@@ -421,7 +418,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_name(
                         cx,
                         attr.span,
-                        fluent::lint::builtin_export_name_static,
+                        fluent::lint_builtin_export_name_static,
                     );
                 }
 
@@ -429,7 +426,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_section(
                         cx,
                         attr.span,
-                        fluent::lint::builtin_link_section_static,
+                        fluent::lint_builtin_link_section_static,
                     );
                 }
             }
@@ -444,14 +441,14 @@ impl EarlyLintPass for UnsafeCode {
                 self.report_overridden_symbol_name(
                     cx,
                     attr.span,
-                    fluent::lint::builtin_no_mangle_method,
+                    fluent::lint_builtin_no_mangle_method,
                 );
             }
             if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
                 self.report_overridden_symbol_name(
                     cx,
                     attr.span,
-                    fluent::lint::builtin_export_name_method,
+                    fluent::lint_builtin_export_name_method,
                 );
             }
         }
@@ -469,9 +466,9 @@ impl EarlyLintPass for UnsafeCode {
         {
             let msg = match ctxt {
                 FnCtxt::Foreign => return,
-                FnCtxt::Free => fluent::lint::builtin_decl_unsafe_fn,
-                FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method,
-                FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method,
+                FnCtxt::Free => fluent::lint_builtin_decl_unsafe_fn,
+                FnCtxt::Assoc(_) if body.is_none() => fluent::lint_builtin_decl_unsafe_method,
+                FnCtxt::Assoc(_) => fluent::lint_builtin_impl_unsafe_method,
             };
             self.report_unsafe(cx, span, msg, |lint| lint);
         }
@@ -566,7 +563,7 @@ impl MissingDoc {
         // It's an option so the crate root can also use this function (it doesn't
         // have a `NodeId`).
         if def_id != CRATE_DEF_ID {
-            if !cx.access_levels.is_exported(def_id) {
+            if !cx.effective_visibilities.is_exported(def_id) {
                 return;
             }
         }
@@ -577,7 +574,7 @@ impl MissingDoc {
             cx.struct_span_lint(
                 MISSING_DOCS,
                 cx.tcx.def_span(def_id),
-                fluent::lint::builtin_missing_doc,
+                fluent::lint_builtin_missing_doc,
                 |lint| lint.set_arg("article", article).set_arg("desc", desc),
             );
         }
@@ -609,9 +606,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
         match it.kind {
             hir::ItemKind::Trait(..) => {
                 // Issue #11592: traits are always considered exported, even when private.
-                if cx.tcx.visibility(it.def_id)
+                if cx.tcx.visibility(it.owner_id)
                     == ty::Visibility::Restricted(
-                        cx.tcx.parent_module_from_def_id(it.def_id.def_id).to_def_id(),
+                        cx.tcx.parent_module_from_def_id(it.owner_id.def_id).to_def_id(),
                     )
                 {
                     return;
@@ -630,15 +627,15 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             _ => return,
         };
 
-        let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
+        let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
 
-        self.check_missing_docs_attrs(cx, it.def_id.def_id, article, desc);
+        self.check_missing_docs_attrs(cx, it.owner_id.def_id, article, desc);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
-        let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
+        let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id());
 
-        self.check_missing_docs_attrs(cx, trait_item.def_id.def_id, article, desc);
+        self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, article, desc);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
@@ -665,13 +662,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             }
         }
 
-        let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
-        self.check_missing_docs_attrs(cx, impl_item.def_id.def_id, article, desc);
+        let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
+        self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, article, desc);
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
-        let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id());
-        self.check_missing_docs_attrs(cx, foreign_item.def_id.def_id, article, desc);
+        let (article, desc) = cx.tcx.article_and_description(foreign_item.owner_id.to_def_id());
+        self.check_missing_docs_attrs(cx, foreign_item.owner_id.def_id, article, desc);
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
@@ -724,7 +721,7 @@ declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS])
 
 impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        if !cx.access_levels.is_reachable(item.def_id.def_id) {
+        if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
             return;
         }
         let (def, ty) = match item.kind {
@@ -732,21 +729,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
-                let def = cx.tcx.adt_def(item.def_id);
+                let def = cx.tcx.adt_def(item.owner_id);
                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
             }
             hir::ItemKind::Union(_, ref ast_generics) => {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
-                let def = cx.tcx.adt_def(item.def_id);
+                let def = cx.tcx.adt_def(item.owner_id);
                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
             }
             hir::ItemKind::Enum(_, ref ast_generics) => {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
-                let def = cx.tcx.adt_def(item.def_id);
+                let def = cx.tcx.adt_def(item.owner_id);
                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
             }
             _ => return,
@@ -755,7 +752,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
             return;
         }
         let param_env = ty::ParamEnv::empty();
-        if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) {
+        if ty.is_copy_modulo_regions(cx.tcx, param_env) {
             return;
         }
         if can_type_implement_copy(
@@ -769,7 +766,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
             cx.struct_span_lint(
                 MISSING_COPY_IMPLEMENTATIONS,
                 item.span,
-                fluent::lint::builtin_missing_copy_impl,
+                fluent::lint_builtin_missing_copy_impl,
                 |lint| lint,
             )
         }
@@ -817,7 +814,7 @@ impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
 
 impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        if !cx.access_levels.is_reachable(item.def_id.def_id) {
+        if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
             return;
         }
 
@@ -844,11 +841,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
             debug!("{:?}", self.impling_types);
         }
 
-        if !self.impling_types.as_ref().unwrap().contains(&item.def_id.def_id) {
+        if !self.impling_types.as_ref().unwrap().contains(&item.owner_id.def_id) {
             cx.struct_span_lint(
                 MISSING_DEBUG_IMPLEMENTATIONS,
                 item.span,
-                fluent::lint::builtin_missing_debug_impl,
+                fluent::lint_builtin_missing_debug_impl,
                 |lint| lint.set_arg("debug", cx.tcx.def_path_str(debug)),
             );
         }
@@ -928,11 +925,11 @@ impl EarlyLintPass for AnonymousParameters {
                         cx.struct_span_lint(
                             ANONYMOUS_PARAMETERS,
                             arg.pat.span,
-                            fluent::lint::builtin_anonymous_params,
+                            fluent::lint_builtin_anonymous_params,
                             |lint| {
                                 lint.span_suggestion(
                                     arg.pat.span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     format!("_: {}", ty_snip),
                                     appl,
                                 )
@@ -976,7 +973,7 @@ impl EarlyLintPass for DeprecatedAttr {
                     cx.struct_span_lint(
                         DEPRECATED,
                         attr.span,
-                        fluent::lint::builtin_deprecated_attr_link,
+                        fluent::lint_builtin_deprecated_attr_link,
                         |lint| {
                             lint.set_arg("name", name)
                                 .set_arg("reason", reason)
@@ -984,7 +981,7 @@ impl EarlyLintPass for DeprecatedAttr {
                                 .span_suggestion_short(
                                     attr.span,
                                     suggestion.map(|s| s.into()).unwrap_or(
-                                        fluent::lint::builtin_deprecated_attr_default_suggestion,
+                                        fluent::lint_builtin_deprecated_attr_default_suggestion,
                                     ),
                                     "",
                                     Applicability::MachineApplicable,
@@ -999,12 +996,12 @@ impl EarlyLintPass for DeprecatedAttr {
             cx.struct_span_lint(
                 DEPRECATED,
                 attr.span,
-                fluent::lint::builtin_deprecated_attr_used,
+                fluent::lint_builtin_deprecated_attr_used,
                 |lint| {
                     lint.set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
                         .span_suggestion_short(
                             attr.span,
-                            fluent::lint::builtin_deprecated_attr_default_suggestion,
+                            fluent::lint_builtin_deprecated_attr_default_suggestion,
                             "",
                             Applicability::MachineApplicable,
                         )
@@ -1039,14 +1036,14 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
             cx.struct_span_lint(
                 UNUSED_DOC_COMMENTS,
                 span,
-                fluent::lint::builtin_unused_doc_comment,
+                fluent::lint_builtin_unused_doc_comment,
                 |lint| {
-                    lint.set_arg("kind", node_kind).span_label(node_span, fluent::lint::label).help(
+                    lint.set_arg("kind", node_kind).span_label(node_span, fluent::label).help(
                         match attr.kind {
                             AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
-                                fluent::lint::plain_help
+                                fluent::plain_help
                             }
-                            AttrKind::DocComment(CommentKind::Block, _) => fluent::lint::block_help,
+                            AttrKind::DocComment(CommentKind::Block, _) => fluent::block_help,
                         },
                     )
                 },
@@ -1167,11 +1164,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                         cx.struct_span_lint(
                             NO_MANGLE_GENERIC_ITEMS,
                             span,
-                            fluent::lint::builtin_no_mangle_generic,
+                            fluent::lint_builtin_no_mangle_generic,
                             |lint| {
                                 lint.span_suggestion_short(
                                     no_mangle_attr.span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     "",
                                     // Use of `#[no_mangle]` suggests FFI intent; correct
                                     // fix may be to monomorphize source by hand
@@ -1197,7 +1194,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                     cx.struct_span_lint(
                         NO_MANGLE_CONST_ITEMS,
                         it.span,
-                        fluent::lint::builtin_const_no_mangle,
+                        fluent::lint_builtin_const_no_mangle,
                         |lint| {
                             // account for "pub const" (#45562)
                             let start = cx
@@ -1211,7 +1208,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                             let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
                             lint.span_suggestion(
                                 const_span,
-                                fluent::lint::suggestion,
+                                fluent::suggestion,
                                 "pub static",
                                 Applicability::MachineApplicable,
                             )
@@ -1229,7 +1226,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                             check_no_mangle_on_generic_fn(
                                 no_mangle_attr,
                                 Some(generics),
-                                cx.tcx.hir().get_generics(it.id.def_id.def_id).unwrap(),
+                                cx.tcx.hir().get_generics(it.id.owner_id.def_id).unwrap(),
                                 it.span,
                             );
                         }
@@ -1279,7 +1276,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
                 cx.struct_span_lint(
                     MUTABLE_TRANSMUTES,
                     expr.span,
-                    fluent::lint::builtin_mutable_transmutes,
+                    fluent::lint_builtin_mutable_transmutes,
                     |lint| lint,
                 );
             }
@@ -1332,7 +1329,7 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
                     cx.struct_span_lint(
                         UNSTABLE_FEATURES,
                         item.span(),
-                        fluent::lint::builtin_unstable_features,
+                        fluent::lint_builtin_unstable_features,
                         |lint| lint,
                     );
                 }
@@ -1388,7 +1385,8 @@ impl UnreachablePub {
         exportable: bool,
     ) {
         let mut applicability = Applicability::MachineApplicable;
-        if cx.tcx.visibility(def_id).is_public() && !cx.access_levels.is_reachable(def_id) {
+        if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id)
+        {
             if vis_span.from_expansion() {
                 applicability = Applicability::MaybeIncorrect;
             }
@@ -1396,18 +1394,13 @@ impl UnreachablePub {
             cx.struct_span_lint(
                 UNREACHABLE_PUB,
                 def_span,
-                fluent::lint::builtin_unreachable_pub,
+                fluent::lint_builtin_unreachable_pub,
                 |lint| {
                     lint.set_arg("what", what);
 
-                    lint.span_suggestion(
-                        vis_span,
-                        fluent::lint::suggestion,
-                        "pub(crate)",
-                        applicability,
-                    );
+                    lint.span_suggestion(vis_span, fluent::suggestion, "pub(crate)", applicability);
                     if exportable {
-                        lint.help(fluent::lint::help);
+                        lint.help(fluent::help);
                     }
                     lint
                 },
@@ -1422,22 +1415,26 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
         if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
             return;
         }
-        self.perform_lint(cx, "item", item.def_id.def_id, item.vis_span, true);
+        self.perform_lint(cx, "item", item.owner_id.def_id, item.vis_span, true);
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
-        self.perform_lint(cx, "item", foreign_item.def_id.def_id, foreign_item.vis_span, true);
+        self.perform_lint(cx, "item", foreign_item.owner_id.def_id, foreign_item.vis_span, true);
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
-        let def_id = cx.tcx.hir().local_def_id(field.hir_id);
+        let map = cx.tcx.hir();
+        let def_id = map.local_def_id(field.hir_id);
+        if matches!(map.get(map.get_parent_node(field.hir_id)), Node::Variant(_)) {
+            return;
+        }
         self.perform_lint(cx, "field", def_id, field.vis_span, false);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
         // Only lint inherent impl items.
-        if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() {
-            self.perform_lint(cx, "item", impl_item.def_id.def_id, impl_item.vis_span, false);
+        if cx.tcx.associated_item(impl_item.owner_id).trait_item_def_id.is_none() {
+            self.perform_lint(cx, "item", impl_item.owner_id.def_id, impl_item.vis_span, false);
         }
     }
 }
@@ -1498,7 +1495,7 @@ impl TypeAliasBounds {
         impl Visitor<'_> for WalkAssocTypes<'_> {
             fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) {
                 if TypeAliasBounds::is_type_variable_assoc(qpath) {
-                    self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help);
+                    self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help);
                 }
                 intravisit::walk_qpath(self, qpath, id)
             }
@@ -1541,11 +1538,11 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
 
         let mut suggested_changing_assoc_types = false;
         if !where_spans.is_empty() {
-            cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint::builtin_type_alias_where_clause, |lint| {
+            cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_where_clause, |lint| {
                 lint.set_span(where_spans);
                 lint.span_suggestion(
                     type_alias_generics.where_clause_span,
-                    fluent::lint::suggestion,
+                    fluent::suggestion,
                     "",
                     Applicability::MachineApplicable,
                 );
@@ -1558,10 +1555,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
         }
 
         if !inline_spans.is_empty() {
-            cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint::builtin_type_alias_generic_bounds, |lint| {
+            cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_generic_bounds, |lint| {
                 lint.set_span(inline_spans);
                 lint.multipart_suggestion(
-                    fluent::lint::suggestion,
+                    fluent::suggestion,
                     inline_sugg,
                     Applicability::MachineApplicable,
                 );
@@ -1646,7 +1643,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
         use rustc_middle::ty::PredicateKind::*;
 
         if cx.tcx.features().trivial_bounds {
-            let predicates = cx.tcx.predicates_of(item.def_id);
+            let predicates = cx.tcx.predicates_of(item.owner_id);
             for &(predicate, span) in predicates.predicates {
                 let predicate_kind_name = match predicate.kind().skip_binder() {
                     Trait(..) => "trait",
@@ -1670,7 +1667,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     cx.struct_span_lint(
                         TRIVIAL_BOUNDS,
                         span,
-                        fluent::lint::builtin_trivial_bounds,
+                        fluent::lint_builtin_trivial_bounds,
                         |lint| {
                             lint.set_arg("predicate_kind_name", predicate_kind_name)
                                 .set_arg("predicate", predicate)
@@ -1775,8 +1772,8 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
         };
 
         if let Some((start, end, join)) = endpoints {
-            let msg = fluent::lint::builtin_ellipsis_inclusive_range_patterns;
-            let suggestion = fluent::lint::suggestion;
+            let msg = fluent::lint_builtin_ellipsis_inclusive_range_patterns;
+            let suggestion = fluent::suggestion;
             if parenthesise {
                 self.node_id = Some(pat.id);
                 let end = expr_to_string(&end);
@@ -1889,7 +1886,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
             if let hir::ItemKind::Mod(..) = it.kind {
             } else {
                 self.items_nameable = false;
-                self.boundary = Some(it.def_id);
+                self.boundary = Some(it.owner_id);
             }
             return;
         }
@@ -1899,14 +1896,14 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
             cx.struct_span_lint(
                 UNNAMEABLE_TEST_ITEMS,
                 attr.span,
-                fluent::lint::builtin_unnameable_test_items,
+                fluent::lint_builtin_unnameable_test_items,
                 |lint| lint,
             );
         }
     }
 
     fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) {
-        if !self.items_nameable && self.boundary == Some(it.def_id) {
+        if !self.items_nameable && self.boundary == Some(it.owner_id) {
             self.items_nameable = true;
         }
     }
@@ -2020,11 +2017,11 @@ impl KeywordIdents {
         cx.struct_span_lint(
             KEYWORD_IDENTS,
             ident.span,
-            fluent::lint::builtin_keyword_idents,
+            fluent::lint_builtin_keyword_idents,
             |lint| {
                 lint.set_arg("kw", ident.clone()).set_arg("next", next_edition).span_suggestion(
                     ident.span,
-                    fluent::lint::suggestion,
+                    fluent::suggestion,
                     format!("r#{}", ident),
                     Applicability::MachineApplicable,
                 )
@@ -2172,7 +2169,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
         use rustc_middle::middle::resolve_lifetime::Region;
 
-        let def_id = item.def_id.def_id;
+        let def_id = item.owner_id.def_id;
         if let hir::ItemKind::Struct(_, ref hir_generics)
         | hir::ItemKind::Enum(_, ref hir_generics)
         | hir::ItemKind::Union(_, ref hir_generics) = item.kind
@@ -2283,10 +2280,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                 cx.struct_span_lint(
                     EXPLICIT_OUTLIVES_REQUIREMENTS,
                     lint_spans.clone(),
-                    fluent::lint::builtin_explicit_outlives,
+                    fluent::lint_builtin_explicit_outlives,
                     |lint| {
                         lint.set_arg("count", bound_count).multipart_suggestion(
-                            fluent::lint::suggestion,
+                            fluent::suggestion,
                             lint_spans
                                 .into_iter()
                                 .map(|span| (span, String::new()))
@@ -2344,17 +2341,17 @@ impl EarlyLintPass for IncompleteFeatures {
                 cx.struct_span_lint(
                     INCOMPLETE_FEATURES,
                     span,
-                    fluent::lint::builtin_incomplete_features,
+                    fluent::lint_builtin_incomplete_features,
                     |lint| {
                         lint.set_arg("name", name);
                         if let Some(n) =
                             rustc_feature::find_feature_issue(name, GateIssue::Language)
                         {
                             lint.set_arg("n", n);
-                            lint.note(fluent::lint::note);
+                            lint.note(fluent::note);
                         }
                         if HAS_MIN_FEATURES.contains(&name) {
-                            lint.help(fluent::lint::help);
+                            lint.help(fluent::help);
                         }
                         lint
                     },
@@ -2467,42 +2464,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
             None
         }
 
-        /// Determines whether the given type is inhabited. `None` means that we don't know.
-        fn ty_inhabited<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<bool> {
-            use rustc_type_ir::sty::TyKind::*;
-            if !cx.tcx.type_uninhabited_from(cx.param_env.and(ty)).is_empty() {
-                // This is definitely uninhabited from some module.
-                return Some(false);
-            }
-            match ty.kind() {
-                Never => Some(false),
-                Int(_) | Uint(_) | Float(_) | Bool | Char | RawPtr(_) => Some(true),
-                // Fallback for more complicated types. (Note that `&!` might be considered
-                // uninhabited so references are "complicated", too.)
-                _ => None,
-            }
-        }
-        /// Determines whether a product type formed from a list of types is inhabited.
-        fn tys_inhabited<'tcx>(
-            cx: &LateContext<'tcx>,
-            tys: impl Iterator<Item = Ty<'tcx>>,
-        ) -> Option<bool> {
-            let mut definitely_inhabited = true; // with no fields, we are definitely inhabited.
-            for ty in tys {
-                match ty_inhabited(cx, ty) {
-                    // If any type is uninhabited, the product is uninhabited.
-                    Some(false) => return Some(false),
-                    // Otherwise go searching for a `None`.
-                    None => {
-                        // We don't know.
-                        definitely_inhabited = false;
-                    }
-                    Some(true) => {}
-                }
-            }
-            if definitely_inhabited { Some(true) } else { None }
-        }
-
         fn variant_find_init_error<'tcx>(
             cx: &LateContext<'tcx>,
             variant: &VariantDef,
@@ -2570,7 +2531,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                         // return `Bound::Excluded`.  (And we have tests checking that we
                         // handle the attribute correctly.)
                         // We don't add a span since users cannot declare such types anyway.
-                        (Bound::Included(lo), _) if lo > 0 => {
+                        (Bound::Included(lo), Bound::Included(hi)) if 0 < lo && lo < hi => {
+                            return Some((format!("`{}` must be non-null", ty), None));
+                        }
+                        (Bound::Included(lo), Bound::Unbounded) if 0 < lo => {
                             return Some((format!("`{}` must be non-null", ty), None));
                         }
                         (Bound::Included(_), _) | (_, Bound::Included(_))
@@ -2599,11 +2563,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                     // And now, enums.
                     let span = cx.tcx.def_span(adt_def.did());
                     let mut potential_variants = adt_def.variants().iter().filter_map(|variant| {
-                        let inhabited = tys_inhabited(
-                            cx,
-                            variant.fields.iter().map(|field| field.ty(cx.tcx, substs)),
-                        );
-                        let definitely_inhabited = match inhabited {
+                        let definitely_inhabited = match variant
+                            .inhabited_predicate(cx.tcx, *adt_def)
+                            .subst(cx.tcx, substs)
+                            .apply_any_module(cx.tcx, cx.param_env)
+                        {
                             // Entirely skip uninhbaited variants.
                             Some(false) => return None,
                             // Forward the others, but remember which ones are definitely inhabited.
@@ -2784,7 +2748,7 @@ impl ClashingExternDeclarations {
     /// Insert a new foreign item into the seen set. If a symbol with the same name already exists
     /// for the item, return its HirId without updating the set.
     fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
-        let did = fi.def_id.to_def_id();
+        let did = fi.owner_id.to_def_id();
         let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
         let name = Symbol::intern(tcx.symbol_name(instance).name);
         if let Some(&hir_id) = self.seen_decls.get(&name) {
@@ -2802,14 +2766,14 @@ impl ClashingExternDeclarations {
     /// symbol's name.
     fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName {
         if let Some((overridden_link_name, overridden_link_name_span)) =
-            tcx.codegen_fn_attrs(fi.def_id).link_name.map(|overridden_link_name| {
+            tcx.codegen_fn_attrs(fi.owner_id).link_name.map(|overridden_link_name| {
                 // FIXME: Instead of searching through the attributes again to get span
                 // 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.def_id.to_def_id(), sym::link_name).unwrap().span,
+                    tcx.get_attr(fi.owner_id.to_def_id(), sym::link_name).unwrap().span,
                 )
             })
         {
@@ -3026,10 +2990,10 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
             let tcx = cx.tcx;
             if let Some(existing_hid) = self.insert(tcx, this_fi) {
                 let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid));
-                let this_decl_ty = tcx.type_of(this_fi.def_id);
+                let this_decl_ty = tcx.type_of(this_fi.owner_id);
                 debug!(
                     "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
-                    existing_hid, existing_decl_ty, this_fi.def_id, this_decl_ty
+                    existing_hid, existing_decl_ty, this_fi.owner_id, this_decl_ty
                 );
                 // Check that the declarations match.
                 if !Self::structurally_same_type(
@@ -3051,9 +3015,9 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
                     // Finally, emit the diagnostic.
 
                     let msg = if orig.get_name() == this_fi.ident.name {
-                        fluent::lint::builtin_clashing_extern_same_name
+                        fluent::lint_builtin_clashing_extern_same_name
                     } else {
-                        fluent::lint::builtin_clashing_extern_diff_name
+                        fluent::lint_builtin_clashing_extern_diff_name
                     };
                     tcx.struct_span_lint_hir(
                         CLASHING_EXTERN_DECLARATIONS,
@@ -3068,14 +3032,8 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
 
                             lint.set_arg("this_fi", this_fi.ident.name)
                                 .set_arg("orig", orig.get_name())
-                                .span_label(
-                                    get_relevant_span(orig_fi),
-                                    fluent::lint::previous_decl_label,
-                                )
-                                .span_label(
-                                    get_relevant_span(this_fi),
-                                    fluent::lint::mismatch_label,
-                                )
+                                .span_label(get_relevant_span(orig_fi), fluent::previous_decl_label)
+                                .span_label(get_relevant_span(this_fi), fluent::mismatch_label)
                                 // FIXME(davidtwco): translatable expected/found
                                 .note_expected_found(&"", expected_str, &"", found_str)
                         },
@@ -3161,8 +3119,8 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
                 cx.struct_span_lint(
                     DEREF_NULLPTR,
                     expr.span,
-                    fluent::lint::builtin_deref_nullptr,
-                    |lint| lint.span_label(expr.span, fluent::lint::label),
+                    fluent::lint_builtin_deref_nullptr,
+                    |lint| lint.span_label(expr.span, fluent::label),
                 );
             }
         }
@@ -3176,6 +3134,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,compile_fail
+    /// # #![feature(asm_experimental_arch)]
     /// use std::arch::asm;
     ///
     /// fn main() {
@@ -3273,7 +3232,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
                     cx.lookup_with_diagnostics(
                             NAMED_ASM_LABELS,
                             Some(target_spans),
-                            fluent::lint::builtin_asm_labels,
+                            fluent::lint_builtin_asm_labels,
                             |lint| lint,
                             BuiltinLintDiagnostics::NamedAsmLabel(
                                 "only local labels of the form `<number>:` should be used in inline asm"
@@ -3310,7 +3269,7 @@ declare_lint! {
     /// explicitly.
     ///
     /// To access a library from a binary target within the same crate,
-    /// use `your_crate_name::` as the path path instead of `lib::`:
+    /// use `your_crate_name::` as the path instead of `lib::`:
     ///
     /// ```rust,compile_fail
     /// // bar/src/lib.rs
@@ -3376,8 +3335,8 @@ impl EarlyLintPass for UnexpectedCfgs {
                     cx.lookup(
                         UNEXPECTED_CFGS,
                         None::<MultiSpan>,
-                        fluent::lint::builtin_unexpected_cli_config_name,
-                        |diag| diag.help(fluent::lint::help).set_arg("name", name),
+                        fluent::lint_builtin_unexpected_cli_config_name,
+                        |diag| diag.help(fluent::help).set_arg("name", name),
                     );
                 }
             }
@@ -3387,9 +3346,9 @@ impl EarlyLintPass for UnexpectedCfgs {
                         cx.lookup(
                             UNEXPECTED_CFGS,
                             None::<MultiSpan>,
-                            fluent::lint::builtin_unexpected_cli_config_value,
+                            fluent::lint_builtin_unexpected_cli_config_value,
                             |diag| {
-                                diag.help(fluent::lint::help)
+                                diag.help(fluent::help)
                                     .set_arg("name", name)
                                     .set_arg("value", value)
                             },
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 74e35afc87d..cec0003ffea 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -31,7 +31,7 @@ use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::middle::stability;
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -542,7 +542,7 @@ pub struct LateContext<'tcx> {
     pub param_env: ty::ParamEnv<'tcx>,
 
     /// Items accessible from the crate being checked.
-    pub access_levels: &'tcx AccessLevels,
+    pub effective_visibilities: &'tcx EffectiveVisibilities,
 
     /// The store of registered lints and the lint levels.
     pub lint_store: &'tcx LintStore,
@@ -574,6 +574,11 @@ pub trait LintContext: Sized {
     fn sess(&self) -> &Session;
     fn lints(&self) -> &LintStore;
 
+    /// Emit a lint at the appropriate level, with an optional associated span and an existing diagnostic.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     fn lookup_with_diagnostics(
         &self,
         lint: &'static Lint,
@@ -872,6 +877,11 @@ pub trait LintContext: Sized {
 
     // FIXME: These methods should not take an Into<MultiSpan> -- instead, callers should need to
     // set the span in their `decorate` function (preferably using set_span).
+    /// Emit a lint at the appropriate level, with an optional associated span.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     fn lookup<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
@@ -893,6 +903,11 @@ pub trait LintContext: Sized {
         self.lookup(lint, Some(span), decorator.msg(), |diag| decorator.decorate_lint(diag));
     }
 
+    /// Emit a lint at the appropriate level, with an associated span.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     fn struct_span_lint<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
@@ -914,6 +929,10 @@ pub trait LintContext: Sized {
     }
 
     /// Emit a lint at the appropriate level, with no associated span.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     fn lint(
         &self,
         lint: &'static Lint,
diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
index e8d307814b9..f9d7466228a 100644
--- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
+++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
@@ -53,8 +53,8 @@ fn enforce_mem_discriminant(
         cx.struct_span_lint(
             ENUM_INTRINSICS_NON_ENUMS,
             expr_span,
-            fluent::lint::enum_intrinsics_mem_discriminant,
-            |lint| lint.set_arg("ty_param", ty_param).span_note(args_span, fluent::lint::note),
+            fluent::lint_enum_intrinsics_mem_discriminant,
+            |lint| lint.set_arg("ty_param", ty_param).span_note(args_span, fluent::note),
         );
     }
 }
@@ -65,8 +65,8 @@ fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, sp
         cx.struct_span_lint(
             ENUM_INTRINSICS_NON_ENUMS,
             span,
-            fluent::lint::enum_intrinsics_mem_variant,
-            |lint| lint.set_arg("ty_param", ty_param).note(fluent::lint::note),
+            fluent::lint_enum_intrinsics_mem_variant,
+            |lint| lint.set_arg("ty_param", ty_param).note(fluent::note),
         );
     }
 }
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 97d012fb611..1a769893f55 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -7,7 +7,7 @@ use rustc_session::lint::Level;
 use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
-#[diag(lint::overruled_attribute, code = "E0453")]
+#[diag(lint_overruled_attribute, code = "E0453")]
 pub struct OverruledAttribute {
     #[primary_span]
     pub span: Span,
@@ -32,24 +32,24 @@ impl AddToDiagnostic for OverruledAttributeSub {
     {
         match self {
             OverruledAttributeSub::DefaultSource { id } => {
-                diag.note(fluent::lint::default_source);
+                diag.note(fluent::lint_default_source);
                 diag.set_arg("id", id);
             }
             OverruledAttributeSub::NodeSource { span, reason } => {
-                diag.span_label(span, fluent::lint::node_source);
+                diag.span_label(span, fluent::lint_node_source);
                 if let Some(rationale) = reason {
                     diag.note(rationale.as_str());
                 }
             }
             OverruledAttributeSub::CommandLineSource => {
-                diag.note(fluent::lint::command_line_source);
+                diag.note(fluent::lint_command_line_source);
             }
         }
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(lint::malformed_attribute, code = "E0452")]
+#[diag(lint_malformed_attribute, code = "E0452")]
 pub struct MalformedAttribute {
     #[primary_span]
     pub span: Span,
@@ -59,16 +59,16 @@ pub struct MalformedAttribute {
 
 #[derive(Subdiagnostic)]
 pub enum MalformedAttributeSub {
-    #[label(lint::bad_attribute_argument)]
+    #[label(lint_bad_attribute_argument)]
     BadAttributeArgument(#[primary_span] Span),
-    #[label(lint::reason_must_be_string_literal)]
+    #[label(lint_reason_must_be_string_literal)]
     ReasonMustBeStringLiteral(#[primary_span] Span),
-    #[label(lint::reason_must_come_last)]
+    #[label(lint_reason_must_come_last)]
     ReasonMustComeLast(#[primary_span] Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(lint::unknown_tool_in_scoped_lint, code = "E0710")]
+#[diag(lint_unknown_tool_in_scoped_lint, code = "E0710")]
 pub struct UnknownToolInScopedLint {
     #[primary_span]
     pub span: Option<Span>,
@@ -79,45 +79,24 @@ pub struct UnknownToolInScopedLint {
 }
 
 #[derive(Diagnostic)]
-#[diag(lint::builtin_ellipsis_inclusive_range_patterns, code = "E0783")]
+#[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = "E0783")]
 pub struct BuiltinEllpisisInclusiveRangePatterns {
     #[primary_span]
     pub span: Span,
-    #[suggestion_short(code = "{replace}", applicability = "machine-applicable")]
+    #[suggestion(style = "short", code = "{replace}", applicability = "machine-applicable")]
     pub suggestion: Span,
     pub replace: String,
 }
 
+#[derive(Subdiagnostic)]
+#[note(lint_requested_level)]
 pub struct RequestedLevel {
     pub level: Level,
     pub lint_name: String,
 }
 
-impl AddToDiagnostic for RequestedLevel {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        diag.note(fluent::lint::requested_level);
-        diag.set_arg(
-            "level",
-            match self.level {
-                Level::Allow => "-A",
-                Level::Warn => "-W",
-                Level::ForceWarn(_) => "--force-warn",
-                Level::Deny => "-D",
-                Level::Forbid => "-F",
-                Level::Expect(_) => {
-                    unreachable!("lints with the level of `expect` should not run this code");
-                }
-            },
-        );
-        diag.set_arg("lint_name", self.lint_name);
-    }
-}
-
 #[derive(Diagnostic)]
-#[diag(lint::unsupported_group, code = "E0602")]
+#[diag(lint_unsupported_group, code = "E0602")]
 pub struct UnsupportedGroup {
     pub lint_group: String,
 }
@@ -133,10 +112,10 @@ impl IntoDiagnostic<'_> for CheckNameUnknown {
         self,
         handler: &Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::lint::check_name_unknown);
+        let mut diag = handler.struct_err(fluent::lint_check_name_unknown);
         diag.code(rustc_errors::error_code!(E0602));
         if let Some(suggestion) = self.suggestion {
-            diag.help(fluent::lint::help);
+            diag.help(fluent::help);
             diag.set_arg("suggestion", suggestion);
         }
         diag.set_arg("lint_name", self.lint_name);
@@ -146,7 +125,7 @@ impl IntoDiagnostic<'_> for CheckNameUnknown {
 }
 
 #[derive(Diagnostic)]
-#[diag(lint::check_name_unknown_tool, code = "E0602")]
+#[diag(lint_check_name_unknown_tool, code = "E0602")]
 pub struct CheckNameUnknownTool {
     pub tool_name: Symbol,
     #[subdiagnostic]
@@ -154,7 +133,7 @@ pub struct CheckNameUnknownTool {
 }
 
 #[derive(Diagnostic)]
-#[diag(lint::check_name_warning)]
+#[diag(lint_check_name_warning)]
 pub struct CheckNameWarning {
     pub msg: String,
     #[subdiagnostic]
@@ -162,7 +141,7 @@ pub struct CheckNameWarning {
 }
 
 #[derive(Diagnostic)]
-#[diag(lint::check_name_deprecated)]
+#[diag(lint_check_name_deprecated)]
 pub struct CheckNameDeprecated {
     pub lint_name: String,
     pub new_name: String,
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 4c3c39734dd..cf8f31bcbd0 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -45,14 +45,14 @@ fn emit_unfulfilled_expectation_lint(
         builtin::UNFULFILLED_LINT_EXPECTATIONS,
         hir_id,
         expectation.emission_span,
-        fluent::lint::expectation,
+        fluent::lint_expectation,
         |lint| {
             if let Some(rationale) = expectation.reason {
                 lint.note(rationale.as_str());
             }
 
             if expectation.is_unfulfilled_lint_expectations {
-                lint.note(fluent::lint::note);
+                lint.note(fluent::note);
             }
 
             lint
diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
index 42557068bd3..7e884e990ce 100644
--- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
+++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
@@ -63,12 +63,12 @@ impl HiddenUnicodeCodepoints {
         cx.struct_span_lint(
             TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
             span,
-            fluent::lint::hidden_unicode_codepoints,
+            fluent::lint_hidden_unicode_codepoints,
             |lint| {
                 lint.set_arg("label", label);
                 lint.set_arg("count", spans.len());
-                lint.span_label(span, fluent::lint::label);
-                lint.note(fluent::lint::note);
+                lint.span_label(span, fluent::label);
+                lint.note(fluent::note);
                 if point_at_inner_spans {
                     for (c, span) in &spans {
                         lint.span_label(*span, format!("{:?}", c));
@@ -76,13 +76,13 @@ impl HiddenUnicodeCodepoints {
                 }
                 if point_at_inner_spans && !spans.is_empty() {
                     lint.multipart_suggestion_with_style(
-                        fluent::lint::suggestion_remove,
+                        fluent::suggestion_remove,
                         spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
                         Applicability::MachineApplicable,
                         SuggestionStyle::HideCodeAlways,
                     );
                     lint.multipart_suggestion(
-                        fluent::lint::suggestion_escape,
+                        fluent::suggestion_escape,
                         spans
                             .into_iter()
                             .map(|(c, span)| {
@@ -104,8 +104,8 @@ impl HiddenUnicodeCodepoints {
                             .collect::<Vec<String>>()
                             .join(", "),
                     );
-                    lint.note(fluent::lint::suggestion_remove);
-                    lint.note(fluent::lint::no_suggestion_note_escape);
+                    lint.note(fluent::suggestion_remove);
+                    lint.note(fluent::no_suggestion_note_escape);
                 }
                 lint
             },
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 8f5e38fdbcc..11e4650cb4b 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -37,11 +37,11 @@ impl LateLintPass<'_> for DefaultHashTypes {
         cx.struct_span_lint(
             DEFAULT_HASH_TYPES,
             path.span,
-            fluent::lint::default_hash_types,
+            fluent::lint_default_hash_types,
             |lint| {
                 lint.set_arg("preferred", replace)
                     .set_arg("used", cx.tcx.item_name(def_id))
-                    .note(fluent::lint::note)
+                    .note(fluent::note)
             },
         );
     }
@@ -86,8 +86,8 @@ impl LateLintPass<'_> for QueryStability {
                 cx.struct_span_lint(
                     POTENTIAL_QUERY_INSTABILITY,
                     span,
-                    fluent::lint::query_instability,
-                    |lint| lint.set_arg("query", cx.tcx.item_name(def_id)).note(fluent::lint::note),
+                    fluent::lint_query_instability,
+                    |lint| lint.set_arg("query", cx.tcx.item_name(def_id)).note(fluent::note),
                 )
             }
         }
@@ -126,11 +126,11 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
             let span = path.span.with_hi(
                 segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
             );
-            cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, fluent::lint::tykind_kind, |lint| {
+            cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, fluent::lint_tykind_kind, |lint| {
                 lint
                     .span_suggestion(
                         span,
-                        fluent::lint::suggestion,
+                        fluent::suggestion,
                         "ty",
                         Applicability::MaybeIncorrect, // ty maybe needs an import
                     )
@@ -193,10 +193,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                             cx.struct_span_lint(
                                 USAGE_OF_TY_TYKIND,
                                 path.span,
-                                fluent::lint::tykind_kind,
+                                fluent::lint_tykind_kind,
                                 |lint| lint.span_suggestion(
                                     span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     "ty",
                                     Applicability::MaybeIncorrect, // ty maybe needs an import
                                 )
@@ -205,18 +205,18 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                         None => cx.struct_span_lint(
                             USAGE_OF_TY_TYKIND,
                             path.span,
-                            fluent::lint::tykind,
-                            |lint| lint.help(fluent::lint::help)
+                            fluent::lint_tykind,
+                            |lint| lint.help(fluent::help)
                         )
                     }
                 } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
                     if path.segments.len() > 1 {
-                        cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, fluent::lint::ty_qualified, |lint| {
+                        cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, fluent::lint_ty_qualified, |lint| {
                             lint
                                 .set_arg("ty", t.clone())
                                 .span_suggestion(
                                     path.span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     t,
                                     // The import probably needs to be changed
                                     Applicability::MaybeIncorrect,
@@ -310,8 +310,8 @@ impl EarlyLintPass for LintPassImpl {
                         cx.struct_span_lint(
                             LINT_PASS_IMPL_WITHOUT_MACRO,
                             lint_pass.path.span,
-                            fluent::lint::lintpass_by_hand,
-                            |lint| lint.help(fluent::lint::help),
+                            fluent::lint_lintpass_by_hand,
+                            |lint| lint.help(fluent::help),
                         )
                     }
                 }
@@ -351,8 +351,8 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
                         cx.struct_span_lint(
                             EXISTING_DOC_KEYWORD,
                             attr.span,
-                            fluent::lint::non_existant_doc_keyword,
-                            |lint| lint.set_arg("keyword", v).help(fluent::lint::help),
+                            fluent::lint_non_existant_doc_keyword,
+                            |lint| lint.set_arg("keyword", v).help(fluent::help),
                         );
                     }
                 }
@@ -414,7 +414,7 @@ impl LateLintPass<'_> for Diagnostics {
             cx.struct_span_lint(
                 DIAGNOSTIC_OUTSIDE_OF_IMPL,
                 span,
-                fluent::lint::diag_out_of_impl,
+                fluent::lint_diag_out_of_impl,
                 |lint| lint,
             )
         }
@@ -435,7 +435,7 @@ impl LateLintPass<'_> for Diagnostics {
             cx.struct_span_lint(
                 UNTRANSLATABLE_DIAGNOSTIC,
                 span,
-                fluent::lint::untranslatable_diag,
+                fluent::lint_untranslatable_diag,
                 |lint| lint,
             )
         }
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index d4e19ef6b22..303fcb1a1d1 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -338,14 +338,14 @@ fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>(
     module_def_id: LocalDefId,
     pass: T,
 ) {
-    let access_levels = &tcx.privacy_access_levels(());
+    let effective_visibilities = &tcx.effective_visibilities(());
 
     let context = LateContext {
         tcx,
         enclosing_body: None,
         cached_typeck_results: Cell::new(None),
         param_env: ty::ParamEnv::empty(),
-        access_levels,
+        effective_visibilities,
         lint_store: unerased_lint_store(tcx),
         last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id),
         generics: None,
@@ -386,14 +386,14 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>(
 }
 
 fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
-    let access_levels = &tcx.privacy_access_levels(());
+    let effective_visibilities = &tcx.effective_visibilities(());
 
     let context = LateContext {
         tcx,
         enclosing_body: None,
         cached_typeck_results: Cell::new(None),
         param_env: ty::ParamEnv::empty(),
-        access_levels,
+        effective_visibilities,
         lint_store: unerased_lint_store(tcx),
         last_node_with_lint_attrs: hir::CRATE_HIR_ID,
         generics: None,
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index be1d7d98aa6..db0a3419e6a 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -960,7 +960,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                                         sp,
                                         "did you mean",
                                         suggestion,
-                                        Applicability::MachineApplicable,
+                                        Applicability::MaybeIncorrect,
                                     );
                                 }
                                 lint
@@ -1069,6 +1069,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
 
     /// Used to emit a lint-related diagnostic based on the current state of
     /// this lint context.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     pub(crate) fn struct_lint(
         &self,
         lint: &'static Lint,
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index fee6e080c4f..5288fc542d7 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -212,7 +212,7 @@ macro_rules! late_lint_mod_passes {
                 TypeLimits: TypeLimits::new(),
                 NonSnakeCase: NonSnakeCase,
                 InvalidNoMangleItems: InvalidNoMangleItems,
-                // Depends on access levels
+                // Depends on effective visibilities
                 UnreachablePub: UnreachablePub,
                 ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
                 InvalidValue: InvalidValue,
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
index 313119637bc..e2d7d5b49f6 100644
--- a/compiler/rustc_lint/src/methods.rs
+++ b/compiler/rustc_lint/src/methods.rs
@@ -93,12 +93,12 @@ fn lint_cstring_as_ptr(
                     cx.struct_span_lint(
                         TEMPORARY_CSTRING_AS_PTR,
                         as_ptr_span,
-                        fluent::lint::cstring_ptr,
+                        fluent::lint_cstring_ptr,
                         |diag| {
-                            diag.span_label(as_ptr_span, fluent::lint::as_ptr_label)
-                                .span_label(unwrap.span, fluent::lint::unwrap_label)
-                                .note(fluent::lint::note)
-                                .help(fluent::lint::help)
+                            diag.span_label(as_ptr_span, fluent::as_ptr_label)
+                                .span_label(unwrap.span, fluent::unwrap_label)
+                                .note(fluent::note)
+                                .help(fluent::help)
                         },
                     );
                 }
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index b2626efb6d7..dea9506acb2 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -183,7 +183,7 @@ impl EarlyLintPass for NonAsciiIdents {
             cx.struct_span_lint(
                 NON_ASCII_IDENTS,
                 sp,
-                fluent::lint::identifier_non_ascii_char,
+                fluent::lint_identifier_non_ascii_char,
                 |lint| lint,
             );
             if check_uncommon_codepoints
@@ -192,7 +192,7 @@ impl EarlyLintPass for NonAsciiIdents {
                 cx.struct_span_lint(
                     UNCOMMON_CODEPOINTS,
                     sp,
-                    fluent::lint::identifier_uncommon_codepoints,
+                    fluent::lint_identifier_uncommon_codepoints,
                     |lint| lint,
                 )
             }
@@ -225,11 +225,11 @@ impl EarlyLintPass for NonAsciiIdents {
                             cx.struct_span_lint(
                                 CONFUSABLE_IDENTS,
                                 sp,
-                                fluent::lint::confusable_identifier_pair,
+                                fluent::lint_confusable_identifier_pair,
                                 |lint| {
                                     lint.set_arg("existing_sym", *existing_symbol)
                                         .set_arg("sym", symbol)
-                                        .span_label(*existing_span, fluent::lint::label)
+                                        .span_label(*existing_span, fluent::label)
                                 },
                             );
                         }
@@ -334,7 +334,7 @@ impl EarlyLintPass for NonAsciiIdents {
                     cx.struct_span_lint(
                         MIXED_SCRIPT_CONFUSABLES,
                         sp,
-                        fluent::lint::mixed_script_confusables,
+                        fluent::lint_mixed_script_confusables,
                         |lint| {
                             let mut includes = String::new();
                             for (idx, ch) in ch_list.into_iter().enumerate() {
@@ -346,8 +346,8 @@ impl EarlyLintPass for NonAsciiIdents {
                             }
                             lint.set_arg("set", script_set.to_string())
                                 .set_arg("includes", includes)
-                                .note(fluent::lint::includes_note)
-                                .note(fluent::lint::note)
+                                .note(fluent::includes_note)
+                                .note(fluent::note)
                         },
                     );
                 }
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 886b686e5e8..6ad2e0294b9 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -119,20 +119,20 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
         arg_span = expn.call_site;
     }
 
-    cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint::non_fmt_panic, |lint| {
+    cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| {
         lint.set_arg("name", symbol);
-        lint.note(fluent::lint::note);
-        lint.note(fluent::lint::more_info_note);
+        lint.note(fluent::note);
+        lint.note(fluent::more_info_note);
         if !is_arg_inside_call(arg_span, span) {
             // No clue where this argument is coming from.
             return lint;
         }
         if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
             // A case of `panic!(format!(..))`.
-            lint.note(fluent::lint::supports_fmt_note);
+            lint.note(fluent::supports_fmt_note);
             if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
                 lint.multipart_suggestion(
-                    fluent::lint::supports_fmt_suggestion,
+                    fluent::supports_fmt_suggestion,
                     vec![
                         (arg_span.until(open.shrink_to_hi()), "".into()),
                         (close.until(arg_span.shrink_to_hi()), "".into()),
@@ -178,7 +178,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
             if suggest_display {
                 lint.span_suggestion_verbose(
                     arg_span.shrink_to_lo(),
-                    fluent::lint::display_suggestion,
+                    fluent::display_suggestion,
                     "\"{}\", ",
                     fmt_applicability,
                 );
@@ -186,7 +186,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                 lint.set_arg("ty", ty);
                 lint.span_suggestion_verbose(
                     arg_span.shrink_to_lo(),
-                    fluent::lint::debug_suggestion,
+                    fluent::debug_suggestion,
                     "\"{:?}\", ",
                     fmt_applicability,
                 );
@@ -196,7 +196,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                 if let Some((open, close, del)) = find_delimiters(cx, span) {
                     lint.set_arg("already_suggested", suggest_display || suggest_debug);
                     lint.multipart_suggestion(
-                        fluent::lint::panic_suggestion,
+                        fluent::panic_suggestion,
                         if del == '(' {
                             vec![(span.until(open), "std::panic::panic_any".into())]
                         } else {
@@ -254,30 +254,25 @@ fn check_panic_str<'tcx>(
                 .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
                 .collect(),
         };
-        cx.struct_span_lint(
-            NON_FMT_PANICS,
-            arg_spans,
-            fluent::lint::non_fmt_panic_unused,
-            |lint| {
-                lint.set_arg("count", n_arguments);
-                lint.note(fluent::lint::note);
-                if is_arg_inside_call(arg.span, span) {
-                    lint.span_suggestion(
-                        arg.span.shrink_to_hi(),
-                        fluent::lint::add_args_suggestion,
-                        ", ...",
-                        Applicability::HasPlaceholders,
-                    );
-                    lint.span_suggestion(
-                        arg.span.shrink_to_lo(),
-                        fluent::lint::add_fmt_suggestion,
-                        "\"{}\", ",
-                        Applicability::MachineApplicable,
-                    );
-                }
-                lint
-            },
-        );
+        cx.struct_span_lint(NON_FMT_PANICS, arg_spans, fluent::lint_non_fmt_panic_unused, |lint| {
+            lint.set_arg("count", n_arguments);
+            lint.note(fluent::note);
+            if is_arg_inside_call(arg.span, span) {
+                lint.span_suggestion(
+                    arg.span.shrink_to_hi(),
+                    fluent::add_args_suggestion,
+                    ", ...",
+                    Applicability::HasPlaceholders,
+                );
+                lint.span_suggestion(
+                    arg.span.shrink_to_lo(),
+                    fluent::add_fmt_suggestion,
+                    "\"{}\", ",
+                    Applicability::MachineApplicable,
+                );
+            }
+            lint
+        });
     } else {
         let brace_spans: Option<Vec<_>> =
             snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| {
@@ -290,14 +285,14 @@ fn check_panic_str<'tcx>(
         cx.struct_span_lint(
             NON_FMT_PANICS,
             brace_spans.unwrap_or_else(|| vec![span]),
-            fluent::lint::non_fmt_panic_braces,
+            fluent::lint_non_fmt_panic_braces,
             |lint| {
                 lint.set_arg("count", count);
-                lint.note(fluent::lint::note);
+                lint.note(fluent::note);
                 if is_arg_inside_call(arg.span, span) {
                     lint.span_suggestion(
                         arg.span.shrink_to_lo(),
-                        fluent::lint::suggestion,
+                        fluent::suggestion,
                         "\"{}\", ",
                         Applicability::MachineApplicable,
                     );
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 6b32e78b910..7e50801f80c 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -139,7 +139,7 @@ impl NonCamelCaseTypes {
             cx.struct_span_lint(
                 NON_CAMEL_CASE_TYPES,
                 ident.span,
-                fluent::lint::non_camel_case_type,
+                fluent::lint_non_camel_case_type,
                 |lint| {
                     let cc = to_camel_case(name);
                     // We cannot provide meaningful suggestions
@@ -147,12 +147,12 @@ impl NonCamelCaseTypes {
                     if *name != cc {
                         lint.span_suggestion(
                             ident.span,
-                            fluent::lint::suggestion,
+                            fluent::suggestion,
                             to_camel_case(name),
                             Applicability::MaybeIncorrect,
                         );
                     } else {
-                        lint.span_label(ident.span, fluent::lint::label);
+                        lint.span_label(ident.span, fluent::label);
                     }
 
                     lint.set_arg("sort", sort);
@@ -284,7 +284,7 @@ impl NonSnakeCase {
         let name = ident.name.as_str();
 
         if !is_snake_case(name) {
-            cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint::non_snake_case, |lint| {
+            cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint_non_snake_case, |lint| {
                 let sc = NonSnakeCase::to_snake_case(name);
                 // We cannot provide meaningful suggestions
                 // if the characters are in the category of "Uppercase Letter".
@@ -298,13 +298,13 @@ impl NonSnakeCase {
                             // Instead, recommend renaming the identifier entirely or, if permitted,
                             // escaping it to create a raw identifier.
                             if sc_ident.name.can_be_raw() {
-                                (fluent::lint::rename_or_convert_suggestion, sc_ident.to_string())
+                                (fluent::rename_or_convert_suggestion, sc_ident.to_string())
                             } else {
-                                lint.note(fluent::lint::cannot_convert_note);
-                                (fluent::lint::rename_suggestion, String::new())
+                                lint.note(fluent::cannot_convert_note);
+                                (fluent::rename_suggestion, String::new())
                             }
                         } else {
-                            (fluent::lint::convert_suggestion, sc.clone())
+                            (fluent::convert_suggestion, sc.clone())
                         };
 
                         lint.span_suggestion(
@@ -314,10 +314,10 @@ impl NonSnakeCase {
                             Applicability::MaybeIncorrect,
                         );
                     } else {
-                        lint.help(fluent::lint::help);
+                        lint.help(fluent::help);
                     }
                 } else {
-                    lint.span_label(ident.span, fluent::lint::label);
+                    lint.span_label(ident.span, fluent::label);
                 }
 
                 lint.set_arg("sort", sort);
@@ -484,7 +484,7 @@ impl NonUpperCaseGlobals {
             cx.struct_span_lint(
                 NON_UPPER_CASE_GLOBALS,
                 ident.span,
-                fluent::lint::non_upper_case_global,
+                fluent::lint_non_upper_case_global,
                 |lint| {
                     let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
                     // We cannot provide meaningful suggestions
@@ -492,12 +492,12 @@ impl NonUpperCaseGlobals {
                     if *name != uc {
                         lint.span_suggestion(
                             ident.span,
-                            fluent::lint::suggestion,
+                            fluent::suggestion,
                             uc,
                             Applicability::MaybeIncorrect,
                         );
                     } else {
-                        lint.span_label(ident.span, fluent::lint::label);
+                        lint.span_label(ident.span, fluent::label);
                     }
 
                     lint.set_arg("sort", sort);
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index 9a62afd3caf..2ef425a1093 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -85,11 +85,11 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
         }
         let expr_span = expr.span;
         let span = expr_span.with_lo(receiver.span.hi());
-        cx.struct_span_lint(NOOP_METHOD_CALL, span, fluent::lint::noop_method_call, |lint| {
+        cx.struct_span_lint(NOOP_METHOD_CALL, span, fluent::lint_noop_method_call, |lint| {
             lint.set_arg("method", call.ident.name)
                 .set_arg("receiver_ty", receiver_ty)
-                .span_label(span, fluent::lint::label)
-                .note(fluent::lint::note)
+                .span_label(span, fluent::label)
+                .note(fluent::note)
         });
     }
 }
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 81b9f55e703..7443d131c64 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -61,7 +61,7 @@ declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
 impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
         let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; };
-        let def_id = item.def_id.def_id.to_def_id();
+        let def_id = item.owner_id.def_id.to_def_id();
         let infcx = &cx.tcx.infer_ctxt().build();
         // For every projection predicate in the opaque type's explicit bounds,
         // check that the type that we're assigning actually satisfies the bounds
@@ -91,14 +91,12 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
             // For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`,
             // e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait`
             // with `impl Send: OtherTrait`.
-            for assoc_pred_and_span in
-                cx.tcx.bound_explicit_item_bounds(proj.projection_ty.item_def_id).transpose_iter()
+            for (assoc_pred, assoc_pred_span) in cx
+                .tcx
+                .bound_explicit_item_bounds(proj.projection_ty.item_def_id)
+                .subst_iter_copied(cx.tcx, &proj.projection_ty.substs)
             {
-                let assoc_pred_span = assoc_pred_and_span.0.1;
-                let assoc_pred = assoc_pred_and_span
-                    .map_bound(|(pred, _)| *pred)
-                    .subst(cx.tcx, &proj.projection_ty.substs)
-                    .fold_with(proj_replacer);
+                let assoc_pred = assoc_pred.fold_with(proj_replacer);
                 let Ok(assoc_pred) = traits::fully_normalize(infcx, traits::ObligationCause::dummy(), cx.param_env, assoc_pred) else {
                     continue;
                 };
@@ -141,19 +139,20 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint::opaque_hidden_inferred_bound)]
+#[diag(lint_opaque_hidden_inferred_bound)]
 struct OpaqueHiddenInferredBoundLint<'tcx> {
     ty: Ty<'tcx>,
     proj_ty: Ty<'tcx>,
-    #[label(lint::specifically)]
+    #[label(specifically)]
     assoc_pred_span: Span,
     #[subdiagnostic]
     add_bound: Option<AddBound<'tcx>>,
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion_verbose(
-    lint::opaque_hidden_inferred_bound_sugg,
+#[suggestion(
+    lint_opaque_hidden_inferred_bound_sugg,
+    style = "verbose",
     applicability = "machine-applicable",
     code = " + {trait_ref}"
 )]
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index 349399b5964..01bface718a 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -32,11 +32,11 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
                     cx.struct_span_lint(
                         PASS_BY_VALUE,
                         ty.span,
-                        fluent::lint::pass_by_value,
+                        fluent::lint_pass_by_value,
                         |lint| {
                             lint.set_arg("ty", t.clone()).span_suggestion(
                                 ty.span,
-                                fluent::lint::suggestion,
+                                fluent::suggestion,
                                 t,
                                 // Changing type of function argument
                                 Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs
index 46c84550e9f..3521de7fc08 100644
--- a/compiler/rustc_lint/src/redundant_semicolon.rs
+++ b/compiler/rustc_lint/src/redundant_semicolon.rs
@@ -51,11 +51,11 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo
         cx.struct_span_lint(
             REDUNDANT_SEMICOLONS,
             span,
-            fluent::lint::redundant_semicolons,
+            fluent::lint_redundant_semicolons,
             |lint| {
                 lint.set_arg("multiple", multiple).span_suggestion(
                     span,
-                    fluent::lint::suggestion,
+                    fluent::suggestion,
                     "",
                     Applicability::MaybeIncorrect,
                 )
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 078465bdce6..f22f38aa2ce 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
         use rustc_middle::ty::PredicateKind::*;
 
-        let predicates = cx.tcx.explicit_predicates_of(item.def_id);
+        let predicates = cx.tcx.explicit_predicates_of(item.owner_id);
         for &(predicate, span) in predicates.predicates {
             let Trait(trait_predicate) = predicate.kind().skip_binder() else {
                 continue
@@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
                 cx.struct_span_lint(
                     DROP_BOUNDS,
                     span,
-                    fluent::lint::drop_trait_constraints,
+                    fluent::lint_drop_trait_constraints,
                     |lint| {
                         lint.set_arg("predicate", predicate)
                             .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
@@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
             if cx.tcx.lang_items().drop_trait() == def_id
                 && let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop)
             {
-                cx.struct_span_lint(DYN_DROP, bound.span, fluent::lint::drop_glue, |lint| {
+                cx.struct_span_lint(DYN_DROP, bound.span, fluent::lint_drop_glue, |lint| {
                     lint.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
                 });
             }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index b6009bd800a..37caab2da0f 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
 use rustc_span::source_map;
 use rustc_span::symbol::sym;
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_span::{Span, Symbol};
 use rustc_target::abi::{Abi, WrappingRange};
 use rustc_target::abi::{Integer, TagEncoding, Variants};
 use rustc_target::spec::abi::Abi as SpecAbi;
@@ -116,8 +116,8 @@ impl TypeLimits {
     }
 }
 
-/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint.
-/// Returns `true` iff the lint was overridden.
+/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint (`expr..MAX+1`).
+/// Returns `true` iff the lint was emitted.
 fn lint_overflowing_range_endpoint<'tcx>(
     cx: &LateContext<'tcx>,
     lit: &hir::Lit,
@@ -140,44 +140,46 @@ fn lint_overflowing_range_endpoint<'tcx>(
         return false;
     }
 
-    let mut overwritten = false;
     // We can suggest using an inclusive range
     // (`..=`) instead only if it is the `end` that is
     // overflowing and only by 1.
-    if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max
-        && let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span)
-    {
-        cx.struct_span_lint(
-            OVERFLOWING_LITERALS,
-            struct_expr.span,
-            fluent::lint::range_endpoint_out_of_range,
-            |lint| {
-                use ast::{LitIntType, LitKind};
-
-                lint.set_arg("ty", ty);
-
-                // We need to preserve the literal's suffix,
-                // as it may determine typing information.
-                let suffix = match lit.node {
-                    LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
-                    LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
-                    LitKind::Int(_, LitIntType::Unsuffixed) => "",
-                    _ => bug!(),
-                };
-                let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
-                lint.span_suggestion(
-                    struct_expr.span,
-                    fluent::lint::suggestion,
-                    suggestion,
-                    Applicability::MachineApplicable,
-                );
-                overwritten = true;
+    if !(eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max) {
+        return false;
+    };
+    let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false };
 
-                lint
-            },
-        );
-    }
-    overwritten
+    cx.struct_span_lint(
+        OVERFLOWING_LITERALS,
+        struct_expr.span,
+        fluent::lint_range_endpoint_out_of_range,
+        |lint| {
+            use ast::{LitIntType, LitKind};
+
+            lint.set_arg("ty", ty);
+
+            // We need to preserve the literal's suffix,
+            // as it may determine typing information.
+            let suffix = match lit.node {
+                LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
+                LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
+                LitKind::Int(_, LitIntType::Unsuffixed) => "",
+                _ => bug!(),
+            };
+            let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
+            lint.span_suggestion(
+                struct_expr.span,
+                fluent::suggestion,
+                suggestion,
+                Applicability::MachineApplicable,
+            );
+
+            lint
+        },
+    );
+
+    // We've just emitted a lint, special cased for `(...)..MAX+1` ranges,
+    // return `true` so the callers don't also emit a lint
+    true
 }
 
 // For `isize` & `usize`, be conservative with the warnings, so that the
@@ -231,7 +233,7 @@ fn report_bin_hex_error(
     cx.struct_span_lint(
         OVERFLOWING_LITERALS,
         expr.span,
-        fluent::lint::overflowing_bin_hex,
+        fluent::lint_overflowing_bin_hex,
         |lint| {
             let (t, actually) = match ty {
                 attr::IntType::SignedInt(t) => {
@@ -251,10 +253,10 @@ fn report_bin_hex_error(
             if negative {
                 // If the value is negative,
                 // emits a note about the value itself, apart from the literal.
-                lint.note(fluent::lint::negative_note);
-                lint.note(fluent::lint::negative_becomes_note);
+                lint.note(fluent::negative_note);
+                lint.note(fluent::negative_becomes_note);
             } else {
-                lint.note(fluent::lint::positive_note);
+                lint.note(fluent::positive_note);
             }
             if let Some(sugg_ty) =
                 get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
@@ -264,12 +266,12 @@ fn report_bin_hex_error(
                     let (sans_suffix, _) = repr_str.split_at(pos);
                     lint.span_suggestion(
                         expr.span,
-                        fluent::lint::suggestion,
+                        fluent::suggestion,
                         format!("{}{}", sans_suffix, sugg_ty),
                         Applicability::MachineApplicable,
                     );
                 } else {
-                    lint.help(fluent::lint::help);
+                    lint.help(fluent::help);
                 }
             }
             lint.set_arg("ty", t)
@@ -358,11 +360,11 @@ fn lint_int_literal<'tcx>(
         }
 
         if lint_overflowing_range_endpoint(cx, lit, v, max, e, t.name_str()) {
-            // The overflowing literal lint was overridden.
+            // The overflowing literal lint was emited by `lint_overflowing_range_endpoint`.
             return;
         }
 
-        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint::overflowing_int, |lint| {
+        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_int, |lint| {
             lint.set_arg("ty", t.name_str())
                 .set_arg(
                     "lit",
@@ -373,13 +375,13 @@ fn lint_int_literal<'tcx>(
                 )
                 .set_arg("min", min)
                 .set_arg("max", max)
-                .note(fluent::lint::note);
+                .note(fluent::note);
 
             if let Some(sugg_ty) =
                 get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
             {
                 lint.set_arg("suggestion_ty", sugg_ty);
-                lint.help(fluent::lint::help);
+                lint.help(fluent::help);
             }
 
             lint
@@ -410,11 +412,11 @@ fn lint_uint_literal<'tcx>(
                         cx.struct_span_lint(
                             OVERFLOWING_LITERALS,
                             par_e.span,
-                            fluent::lint::only_cast_u8_to_char,
+                            fluent::lint_only_cast_u8_to_char,
                             |lint| {
                                 lint.span_suggestion(
                                     par_e.span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     format!("'\\u{{{:X}}}'", lit_val),
                                     Applicability::MachineApplicable,
                                 )
@@ -427,7 +429,7 @@ fn lint_uint_literal<'tcx>(
             }
         }
         if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, t.name_str()) {
-            // The overflowing literal lint was overridden.
+            // The overflowing literal lint was emited by `lint_overflowing_range_endpoint`.
             return;
         }
         if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
@@ -441,7 +443,7 @@ fn lint_uint_literal<'tcx>(
             );
             return;
         }
-        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint::overflowing_uint, |lint| {
+        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_uint, |lint| {
             lint.set_arg("ty", t.name_str())
                 .set_arg(
                     "lit",
@@ -452,7 +454,7 @@ fn lint_uint_literal<'tcx>(
                 )
                 .set_arg("min", min)
                 .set_arg("max", max)
-                .note(fluent::lint::note)
+                .note(fluent::note)
         });
     }
 }
@@ -485,7 +487,7 @@ fn lint_literal<'tcx>(
                 cx.struct_span_lint(
                     OVERFLOWING_LITERALS,
                     e.span,
-                    fluent::lint::overflowing_literal,
+                    fluent::lint_overflowing_literal,
                     |lint| {
                         lint.set_arg("ty", t.name_str())
                             .set_arg(
@@ -495,7 +497,7 @@ fn lint_literal<'tcx>(
                                     .span_to_snippet(lit.span)
                                     .expect("must get snippet from literal"),
                             )
-                            .note(fluent::lint::note)
+                            .note(fluent::note)
                     },
                 );
             }
@@ -518,7 +520,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
                     cx.struct_span_lint(
                         UNUSED_COMPARISONS,
                         e.span,
-                        fluent::lint::unused_comparisons,
+                        fluent::lint_unused_comparisons,
                         |lint| lint,
                     );
                 }
@@ -840,8 +842,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             self.emit_ffi_unsafe_type_lint(
                 ty,
                 sp,
-                fluent::lint::improper_ctypes_array_reason,
-                Some(fluent::lint::improper_ctypes_array_help),
+                fluent::lint_improper_ctypes_array_reason,
+                Some(fluent::lint_improper_ctypes_array_help),
             );
             true
         } else {
@@ -884,7 +886,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             } else {
                 // All fields are ZSTs; this means that the type should behave
                 // like (), which is FFI-unsafe
-                FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_struct_zst, help: None }
+                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
             }
         } else {
             // We can't completely trust repr(C) markings; make sure the fields are
@@ -898,7 +900,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     FfiPhantom(..) if def.is_enum() => {
                         return FfiUnsafe {
                             ty,
-                            reason: fluent::lint::improper_ctypes_enum_phantomdata,
+                            reason: fluent::lint_improper_ctypes_enum_phantomdata,
                             help: None,
                         };
                     }
@@ -929,12 +931,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         match *ty.kind() {
             ty::Adt(def, substs) => {
                 if def.is_box() && matches!(self.mode, CItemKind::Definition) {
-                    if ty.boxed_ty().is_sized(tcx.at(DUMMY_SP), self.cx.param_env) {
+                    if ty.boxed_ty().is_sized(tcx, self.cx.param_env) {
                         return FfiSafe;
                     } else {
                         return FfiUnsafe {
                             ty,
-                            reason: fluent::lint::improper_ctypes_box,
+                            reason: fluent::lint_improper_ctypes_box,
                             help: None,
                         };
                     }
@@ -948,14 +950,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             return FfiUnsafe {
                                 ty,
                                 reason: if def.is_struct() {
-                                    fluent::lint::improper_ctypes_struct_layout_reason
+                                    fluent::lint_improper_ctypes_struct_layout_reason
                                 } else {
-                                    fluent::lint::improper_ctypes_union_layout_reason
+                                    fluent::lint_improper_ctypes_union_layout_reason
                                 },
                                 help: if def.is_struct() {
-                                    Some(fluent::lint::improper_ctypes_struct_layout_help)
+                                    Some(fluent::lint_improper_ctypes_struct_layout_help)
                                 } else {
-                                    Some(fluent::lint::improper_ctypes_union_layout_help)
+                                    Some(fluent::lint_improper_ctypes_union_layout_help)
                                 },
                             };
                         }
@@ -966,9 +968,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             return FfiUnsafe {
                                 ty,
                                 reason: if def.is_struct() {
-                                    fluent::lint::improper_ctypes_struct_non_exhaustive
+                                    fluent::lint_improper_ctypes_struct_non_exhaustive
                                 } else {
-                                    fluent::lint::improper_ctypes_union_non_exhaustive
+                                    fluent::lint_improper_ctypes_union_non_exhaustive
                                 },
                                 help: None,
                             };
@@ -978,14 +980,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             return FfiUnsafe {
                                 ty,
                                 reason: if def.is_struct() {
-                                    fluent::lint::improper_ctypes_struct_fieldless_reason
+                                    fluent::lint_improper_ctypes_struct_fieldless_reason
                                 } else {
-                                    fluent::lint::improper_ctypes_union_fieldless_reason
+                                    fluent::lint_improper_ctypes_union_fieldless_reason
                                 },
                                 help: if def.is_struct() {
-                                    Some(fluent::lint::improper_ctypes_struct_fieldless_help)
+                                    Some(fluent::lint_improper_ctypes_struct_fieldless_help)
                                 } else {
-                                    Some(fluent::lint::improper_ctypes_union_fieldless_help)
+                                    Some(fluent::lint_improper_ctypes_union_fieldless_help)
                                 },
                             };
                         }
@@ -1006,8 +1008,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             if repr_nullable_ptr(self.cx, ty, self.mode).is_none() {
                                 return FfiUnsafe {
                                     ty,
-                                    reason: fluent::lint::improper_ctypes_enum_repr_reason,
-                                    help: Some(fluent::lint::improper_ctypes_enum_repr_help),
+                                    reason: fluent::lint_improper_ctypes_enum_repr_reason,
+                                    help: Some(fluent::lint_improper_ctypes_enum_repr_help),
                                 };
                             }
                         }
@@ -1015,7 +1017,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
                             return FfiUnsafe {
                                 ty,
-                                reason: fluent::lint::improper_ctypes_non_exhaustive,
+                                reason: fluent::lint_improper_ctypes_non_exhaustive,
                                 help: None,
                             };
                         }
@@ -1026,7 +1028,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             if is_non_exhaustive && !variant.def_id.is_local() {
                                 return FfiUnsafe {
                                     ty,
-                                    reason: fluent::lint::improper_ctypes_non_exhaustive_variant,
+                                    reason: fluent::lint_improper_ctypes_non_exhaustive_variant,
                                     help: None,
                                 };
                             }
@@ -1044,12 +1046,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
             ty::Char => FfiUnsafe {
                 ty,
-                reason: fluent::lint::improper_ctypes_char_reason,
-                help: Some(fluent::lint::improper_ctypes_char_help),
+                reason: fluent::lint_improper_ctypes_char_reason,
+                help: Some(fluent::lint_improper_ctypes_char_help),
             },
 
             ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => {
-                FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_128bit, help: None }
+                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None }
             }
 
             // Primitive types with a stable representation.
@@ -1057,30 +1059,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
             ty::Slice(_) => FfiUnsafe {
                 ty,
-                reason: fluent::lint::improper_ctypes_slice_reason,
-                help: Some(fluent::lint::improper_ctypes_slice_help),
+                reason: fluent::lint_improper_ctypes_slice_reason,
+                help: Some(fluent::lint_improper_ctypes_slice_help),
             },
 
             ty::Dynamic(..) => {
-                FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_dyn, help: None }
+                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_dyn, help: None }
             }
 
             ty::Str => FfiUnsafe {
                 ty,
-                reason: fluent::lint::improper_ctypes_str_reason,
-                help: Some(fluent::lint::improper_ctypes_str_help),
+                reason: fluent::lint_improper_ctypes_str_reason,
+                help: Some(fluent::lint_improper_ctypes_str_help),
             },
 
             ty::Tuple(..) => FfiUnsafe {
                 ty,
-                reason: fluent::lint::improper_ctypes_tuple_reason,
-                help: Some(fluent::lint::improper_ctypes_tuple_help),
+                reason: fluent::lint_improper_ctypes_tuple_reason,
+                help: Some(fluent::lint_improper_ctypes_tuple_help),
             },
 
             ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _)
                 if {
                     matches!(self.mode, CItemKind::Definition)
-                        && ty.is_sized(self.cx.tcx.at(DUMMY_SP), self.cx.param_env)
+                        && ty.is_sized(self.cx.tcx, self.cx.param_env)
                 } =>
             {
                 FfiSafe
@@ -1105,8 +1107,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 if self.is_internal_abi(sig.abi()) {
                     return FfiUnsafe {
                         ty,
-                        reason: fluent::lint::improper_ctypes_fnptr_reason,
-                        help: Some(fluent::lint::improper_ctypes_fnptr_help),
+                        reason: fluent::lint_improper_ctypes_fnptr_reason,
+                        help: Some(fluent::lint_improper_ctypes_fnptr_help),
                     };
                 }
 
@@ -1137,7 +1139,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             // While opaque types are checked for earlier, if a projection in a struct field
             // normalizes to an opaque type, then it will reach this branch.
             ty::Opaque(..) => {
-                FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_opaque, help: None }
+                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_opaque, help: None }
             }
 
             // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
@@ -1171,21 +1173,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
         };
 
-        self.cx.struct_span_lint(lint, sp, fluent::lint::improper_ctypes, |lint| {
+        self.cx.struct_span_lint(lint, sp, fluent::lint_improper_ctypes, |lint| {
             let item_description = match self.mode {
                 CItemKind::Declaration => "block",
                 CItemKind::Definition => "fn",
             };
             lint.set_arg("ty", ty);
             lint.set_arg("desc", item_description);
-            lint.span_label(sp, fluent::lint::label);
+            lint.span_label(sp, fluent::label);
             if let Some(help) = help {
                 lint.help(help);
             }
             lint.note(note);
             if let ty::Adt(def, _) = ty.kind() {
                 if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
-                    lint.span_note(sp, fluent::lint::note);
+                    lint.span_note(sp, fluent::note);
                 }
             }
             lint
@@ -1222,7 +1224,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         }
 
         if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() {
-            self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint::improper_ctypes_opaque, None);
+            self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None);
             true
         } else {
             false
@@ -1267,7 +1269,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 self.emit_ffi_unsafe_type_lint(
                     ty,
                     sp,
-                    fluent::lint::improper_ctypes_only_phantomdata,
+                    fluent::lint_improper_ctypes_only_phantomdata,
                     None,
                 );
             }
@@ -1358,7 +1360,7 @@ declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);
 impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
         if let hir::ItemKind::Enum(ref enum_definition, _) = it.kind {
-            let t = cx.tcx.type_of(it.def_id);
+            let t = cx.tcx.type_of(it.owner_id);
             let ty = cx.tcx.erase_regions(t);
             let Ok(layout) = cx.layout_of(ty) else { return };
             let Variants::Multiple {
@@ -1401,7 +1403,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
                 cx.struct_span_lint(
                     VARIANT_SIZE_DIFFERENCES,
                     enum_definition.variants[largest_index].span,
-                    fluent::lint::variant_size_differences,
+                    fluent::lint_variant_size_differences,
                     |lint| lint.set_arg("largest", largest),
                 );
             }
@@ -1511,15 +1513,15 @@ impl InvalidAtomicOrdering {
     fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
             && let Some((ordering_arg, invalid_ordering, msg)) = match method {
-                sym::load => Some((&args[0], sym::Release, fluent::lint::atomic_ordering_load)),
-                sym::store => Some((&args[1], sym::Acquire, fluent::lint::atomic_ordering_store)),
+                sym::load => Some((&args[0], sym::Release, fluent::lint_atomic_ordering_load)),
+                sym::store => Some((&args[1], sym::Acquire, fluent::lint_atomic_ordering_store)),
                 _ => None,
             }
             && let Some(ordering) = Self::match_ordering(cx, ordering_arg)
             && (ordering == invalid_ordering || ordering == sym::AcqRel)
         {
             cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, msg, |lint| {
-                lint.help(fluent::lint::help)
+                lint.help(fluent::help)
             });
         }
     }
@@ -1531,9 +1533,9 @@ impl InvalidAtomicOrdering {
             && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence))
             && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed)
         {
-            cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, fluent::lint::atomic_ordering_fence, |lint| {
+            cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, fluent::lint_atomic_ordering_fence, |lint| {
                 lint
-                    .help(fluent::lint::help)
+                    .help(fluent::help)
             });
         }
     }
@@ -1552,7 +1554,7 @@ impl InvalidAtomicOrdering {
 
         if matches!(fail_ordering, sym::Release | sym::AcqRel) {
             #[derive(LintDiagnostic)]
-            #[diag(lint::atomic_ordering_invalid)]
+            #[diag(lint_atomic_ordering_invalid)]
             #[help]
             struct InvalidAtomicOrderingDiag {
                 method: Symbol,
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 787c9518b50..46706e49844 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -7,6 +7,7 @@ use rustc_errors::{fluent, pluralize, Applicability, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_infer::traits::util::elaborate_predicates_with_span;
 use rustc_middle::ty::adjustment;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::Symbol;
@@ -154,12 +155,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
         };
 
         if let Some(must_use_op) = must_use_op {
-            cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint::unused_op, |lint| {
+            cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| {
                 lint.set_arg("op", must_use_op)
-                    .span_label(expr.span, fluent::lint::label)
+                    .span_label(expr.span, fluent::label)
                     .span_suggestion_verbose(
                         expr.span.shrink_to_lo(),
-                        fluent::lint::suggestion,
+                        fluent::suggestion,
                         "let _ = ",
                         Applicability::MachineApplicable,
                     )
@@ -168,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
         }
 
         if !(type_permits_lack_of_use || fn_warned || op_warned) {
-            cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint::unused_result, |lint| {
+            cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| {
                 lint.set_arg("ty", ty)
             });
         }
@@ -204,10 +205,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                 ty::Adt(def, _) => check_must_use_def(cx, def.did(), span, descr_pre, descr_post),
                 ty::Opaque(def, _) => {
                     let mut has_emitted = false;
-                    for &(predicate, _) in cx.tcx.explicit_item_bounds(def) {
+                    for obligation in elaborate_predicates_with_span(
+                        cx.tcx,
+                        cx.tcx.explicit_item_bounds(def).iter().cloned(),
+                    ) {
                         // We only look at the `DefId`, so it is safe to skip the binder here.
                         if let ty::PredicateKind::Trait(ref poly_trait_predicate) =
-                            predicate.kind().skip_binder()
+                            obligation.predicate.kind().skip_binder()
                         {
                             let def_id = poly_trait_predicate.trait_ref.def_id;
                             let descr_pre =
@@ -268,14 +272,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                     cx.struct_span_lint(
                         UNUSED_MUST_USE,
                         span,
-                        fluent::lint::unused_closure,
+                        fluent::lint_unused_closure,
                         |lint| {
                             // FIXME(davidtwco): this isn't properly translatable because of the
                             // pre/post strings
                             lint.set_arg("count", plural_len)
                                 .set_arg("pre", descr_pre)
                                 .set_arg("post", descr_post)
-                                .note(fluent::lint::note)
+                                .note(fluent::note)
                         },
                     );
                     true
@@ -284,14 +288,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                     cx.struct_span_lint(
                         UNUSED_MUST_USE,
                         span,
-                        fluent::lint::unused_generator,
+                        fluent::lint_unused_generator,
                         |lint| {
                             // FIXME(davidtwco): this isn't properly translatable because of the
                             // pre/post strings
                             lint.set_arg("count", plural_len)
                                 .set_arg("pre", descr_pre)
                                 .set_arg("post", descr_post)
-                                .note(fluent::lint::note)
+                                .note(fluent::note)
                         },
                     );
                     true
@@ -313,7 +317,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
             descr_post_path: &str,
         ) -> bool {
             if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
-                cx.struct_span_lint(UNUSED_MUST_USE, span, fluent::lint::unused_def, |lint| {
+                cx.struct_span_lint(UNUSED_MUST_USE, span, fluent::lint_unused_def, |lint| {
                     // FIXME(davidtwco): this isn't properly translatable because of the pre/post
                     // strings
                     lint.set_arg("pre", descr_pre_path);
@@ -365,17 +369,17 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
                     cx.struct_span_lint(
                         PATH_STATEMENTS,
                         s.span,
-                        fluent::lint::path_statement_drop,
+                        fluent::lint_path_statement_drop,
                         |lint| {
                             if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
                                 lint.span_suggestion(
                                     s.span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     format!("drop({});", snippet),
                                     Applicability::MachineApplicable,
                                 );
                             } else {
-                                lint.span_help(s.span, fluent::lint::suggestion);
+                                lint.span_help(s.span, fluent::suggestion);
                             }
                             lint
                         },
@@ -384,7 +388,7 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
                     cx.struct_span_lint(
                         PATH_STATEMENTS,
                         s.span,
-                        fluent::lint::path_statement_no_effect,
+                        fluent::lint_path_statement_no_effect,
                         |lint| lint,
                     );
                 }
@@ -557,7 +561,7 @@ trait UnusedDelimLint {
         } else {
             MultiSpan::from(value_span)
         };
-        cx.struct_span_lint(self.lint(), primary_span, fluent::lint::unused_delim, |lint| {
+        cx.struct_span_lint(self.lint(), primary_span, fluent::lint_unused_delim, |lint| {
             lint.set_arg("delim", Self::DELIM_STR);
             lint.set_arg("item", msg);
             if let Some((lo, hi)) = spans {
@@ -566,7 +570,7 @@ trait UnusedDelimLint {
                     (hi, if keep_space.1 { " ".into() } else { "".into() }),
                 ];
                 lint.multipart_suggestion(
-                    fluent::lint::suggestion,
+                    fluent::suggestion,
                     replacement,
                     Applicability::MachineApplicable,
                 );
@@ -1142,7 +1146,7 @@ impl UnusedImportBraces {
             cx.struct_span_lint(
                 UNUSED_IMPORT_BRACES,
                 item.span,
-                fluent::lint::unused_import_braces,
+                fluent::lint_unused_import_braces,
                 |lint| lint.set_arg("node", node_name),
             );
         }
@@ -1197,9 +1201,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
                     UNUSED_ALLOCATION,
                     e.span,
                     match m {
-                        adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation,
+                        adjustment::AutoBorrowMutability::Not => fluent::lint_unused_allocation,
                         adjustment::AutoBorrowMutability::Mut { .. } => {
-                            fluent::lint::unused_allocation_mut
+                            fluent::lint_unused_allocation_mut
                         }
                     },
                     |lint| lint,
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 4e30aa5eaba..389f3ccf72a 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1427,6 +1427,7 @@ declare_lint! {
     "trait-object types were treated as different depending on marker-trait order",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
 
@@ -1982,73 +1983,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `proc_macro_derive_resolution_fallback` lint detects proc macro
-    /// derives using inaccessible names from parent modules.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,ignore (proc-macro)
-    /// // foo.rs
-    /// #![crate_type = "proc-macro"]
-    ///
-    /// extern crate proc_macro;
-    ///
-    /// use proc_macro::*;
-    ///
-    /// #[proc_macro_derive(Foo)]
-    /// pub fn foo1(a: TokenStream) -> TokenStream {
-    ///     drop(a);
-    ///     "mod __bar { static mut BAR: Option<Something> = None; }".parse().unwrap()
-    /// }
-    /// ```
-    ///
-    /// ```rust,ignore (needs-dependency)
-    /// // bar.rs
-    /// #[macro_use]
-    /// extern crate foo;
-    ///
-    /// struct Something;
-    ///
-    /// #[derive(Foo)]
-    /// struct Another;
-    ///
-    /// fn main() {}
-    /// ```
-    ///
-    /// This will produce:
-    ///
-    /// ```text
-    /// warning: cannot find type `Something` in this scope
-    ///  --> src/main.rs:8:10
-    ///   |
-    /// 8 | #[derive(Foo)]
-    ///   |          ^^^ names from parent modules are not accessible without an explicit import
-    ///   |
-    ///   = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
-    ///   = 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 #50504 <https://github.com/rust-lang/rust/issues/50504>
-    /// ```
-    ///
-    /// ### Explanation
-    ///
-    /// If a proc-macro generates a module, the compiler unintentionally
-    /// allowed items in that module to refer to items in the crate root
-    /// without importing them. This is a [future-incompatible] lint to
-    /// transition this to a hard error in the future. See [issue #50504] for
-    /// more details.
-    ///
-    /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504
-    /// [future-incompatible]: ../index.md#future-incompatible-lints
-    pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
-    Deny,
-    "detects proc macro derives using inaccessible names from parent modules",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
-    };
-}
-
-declare_lint! {
     /// The `macro_use_extern_crate` lint detects the use of the
     /// [`macro_use` attribute].
     ///
@@ -2878,7 +2812,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust
-    /// #![feature(naked_functions)]
+    /// #![feature(asm_experimental_arch, naked_functions)]
     ///
     /// use std::arch::asm;
     ///
@@ -3286,7 +3220,6 @@ declare_lint_pass! {
         UNSTABLE_NAME_COLLISIONS,
         IRREFUTABLE_LET_PATTERNS,
         WHERE_CLAUSES_OBJECT_SAFETY,
-        PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
         MACRO_USE_EXTERN_CRATE,
         MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
         ILL_FORMED_ATTRIBUTE_INPUT,
@@ -3937,7 +3870,7 @@ declare_lint! {
     ///
     /// The compiler disables the automatic implementation if an explicit one
     /// exists for given type constructor. The exact rules governing this
-    /// are currently unsound and quite subtle and and will be modified in the future.
+    /// are currently unsound, quite subtle, and will be modified in the future.
     /// This change will cause the automatic implementation to be disabled in more
     /// cases, potentially breaking some code.
     pub SUSPICIOUS_AUTO_TRAIT_IMPLS,
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 879a3b660b4..18d37d95a83 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -69,7 +69,9 @@ extern "C" void LLVMInitializePasses() {
   initializeAnalysis(Registry);
   initializeTransformUtils(Registry);
   initializeInstCombine(Registry);
+#if LLVM_VERSION_LT(16, 0)
   initializeInstrumentation(Registry);
+#endif
   initializeTarget(Registry);
 }
 
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 8cf307df5a5..ab38a9ccc8f 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -40,7 +40,7 @@ impl<'a> DiagnosticDerive<'a> {
                     span_err(builder.span, "diagnostic slug not specified")
                         .help(&format!(
                             "specify the slug as the first argument to the `#[diag(...)]` \
-                            attribute, such as `#[diag(hir_analysis::example_error)]`",
+                            attribute, such as `#[diag(hir_analysis_example_error)]`",
                         ))
                         .emit();
                     return DiagnosticDeriveError::ErrorHandled.to_compile_error();
@@ -69,6 +69,8 @@ impl<'a> DiagnosticDerive<'a> {
                     for @Self
                 where G: rustc_errors::EmissionGuarantee
             {
+
+                #[track_caller]
                 fn into_diagnostic(
                     self,
                     #handler: &'__diagnostic_handler_sess rustc_errors::Handler
@@ -121,7 +123,7 @@ impl<'a> LintDiagnosticDerive<'a> {
                     span_err(builder.span, "diagnostic slug not specified")
                         .help(&format!(
                             "specify the slug as the first argument to the attribute, such as \
-                            `#[diag(compiletest::example)]`",
+                            `#[diag(compiletest_example)]`",
                         ))
                         .emit();
                     return DiagnosticDeriveError::ErrorHandled.to_compile_error();
@@ -133,6 +135,7 @@ impl<'a> LintDiagnosticDerive<'a> {
         let diag = &builder.diag;
         structure.gen_impl(quote! {
             gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
+                #[track_caller]
                 fn decorate_lint<'__b>(
                     self,
                     #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()>
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index dcbe89251cb..3ea83fd09c7 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -5,7 +5,7 @@ use crate::diagnostics::error::{
     DiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
-    build_field_mapping, report_error_if_not_applied_to_span, report_type_error,
+    build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error,
     should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, FieldMap,
     HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
 };
@@ -152,8 +152,12 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
     fn parse_subdiag_attribute(
         &self,
         attr: &Attribute,
-    ) -> Result<(SubdiagnosticKind, Path), DiagnosticDeriveError> {
-        let (subdiag, slug) = SubdiagnosticKind::from_attr(attr, self)?;
+    ) -> Result<Option<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
+        let Some((subdiag, slug)) = SubdiagnosticKind::from_attr(attr, self)? else {
+            // Some attributes aren't errors - like documentation comments - but also aren't
+            // subdiagnostics.
+            return Ok(None);
+        };
 
         if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag {
             let meta = attr.parse_meta()?;
@@ -170,7 +174,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
             SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
         });
 
-        Ok((subdiag, slug))
+        Ok(Some((subdiag, slug)))
     }
 
     /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
@@ -182,6 +186,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
     ) -> Result<TokenStream, DiagnosticDeriveError> {
         let diag = &self.parent.diag;
 
+        // Always allow documentation comments.
+        if is_doc_comment(attr) {
+            return Ok(quote! {});
+        }
+
         let name = attr.path.segments.last().unwrap().ident.to_string();
         let name = name.as_str();
         let meta = attr.parse_meta()?;
@@ -250,7 +259,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
             return Ok(tokens);
         }
 
-        let (subdiag, slug) = self.parse_subdiag_attribute(attr)?;
+        let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else {
+            // Some attributes aren't errors - like documentation comments - but also aren't
+            // subdiagnostics.
+            return Ok(quote! {});
+        };
         let fn_ident = format_ident!("{}", subdiag);
         match subdiag {
             SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
@@ -291,6 +304,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
             .attrs
             .iter()
             .map(move |attr| {
+                // Always allow documentation comments.
+                if is_doc_comment(attr) {
+                    return quote! {};
+                }
+
                 let name = attr.path.segments.last().unwrap().ident.to_string();
                 let needs_clone =
                     name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
@@ -397,8 +415,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
             _ => (),
         }
 
-        let (subdiag, slug) = self.parse_subdiag_attribute(attr)?;
-
+        let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else {
+            // Some attributes aren't errors - like documentation comments - but also aren't
+            // subdiagnostics.
+            return Ok(quote! {});
+        };
         let fn_ident = format_ident!("{}", subdiag);
         match subdiag {
             SubdiagnosticKind::Label => {
@@ -433,7 +454,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
 
                 self.formatting_init.extend(code_init);
                 Ok(quote! {
-                    #diag.span_suggestion_with_style(
+                    #diag.span_suggestions_with_style(
                         #span_field,
                         rustc_errors::fluent::#slug,
                         #code_field,
diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs
index f7d8b494ee2..3e447c94ef1 100644
--- a/compiler/rustc_macros/src/diagnostics/fluent.rs
+++ b/compiler/rustc_macros/src/diagnostics/fluent.rs
@@ -25,18 +25,18 @@ use syn::{
 use unic_langid::langid;
 
 struct Resource {
-    ident: Ident,
+    krate: Ident,
     #[allow(dead_code)]
     fat_arrow_token: token::FatArrow,
-    resource: LitStr,
+    resource_path: LitStr,
 }
 
 impl Parse for Resource {
     fn parse(input: ParseStream<'_>) -> Result<Self> {
         Ok(Resource {
-            ident: input.parse()?,
+            krate: input.parse()?,
             fat_arrow_token: input.parse()?,
-            resource: input.parse()?,
+            resource_path: input.parse()?,
         })
     }
 }
@@ -94,19 +94,20 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
     // diagnostics.
     let mut previous_defns = HashMap::new();
 
+    // Set of Fluent attribute names already output, to avoid duplicate type errors - any given
+    // constant created for a given attribute is the same.
+    let mut previous_attrs = HashSet::new();
+
     let mut includes = TokenStream::new();
     let mut generated = TokenStream::new();
-    for res in resources.0 {
-        let ident_span = res.ident.span().unwrap();
-        let path_span = res.resource.span().unwrap();
 
-        // Set of Fluent attribute names already output, to avoid duplicate type errors - any given
-        // constant created for a given attribute is the same.
-        let mut previous_attrs = HashSet::new();
+    for res in resources.0 {
+        let krate_span = res.krate.span().unwrap();
+        let path_span = res.resource_path.span().unwrap();
 
-        let relative_ftl_path = res.resource.value();
+        let relative_ftl_path = res.resource_path.value();
         let absolute_ftl_path =
-            invocation_relative_path_to_absolute(ident_span, &relative_ftl_path);
+            invocation_relative_path_to_absolute(krate_span, &relative_ftl_path);
         // As this macro also outputs an `include_str!` for this file, the macro will always be
         // re-executed when the file changes.
         let mut resource_file = match File::open(absolute_ftl_path) {
@@ -185,7 +186,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
 
         let mut constants = TokenStream::new();
         for entry in resource.entries() {
-            let span = res.ident.span();
+            let span = res.krate.span();
             if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry {
                 let _ = previous_defns.entry(name.to_string()).or_insert(path_span);
 
@@ -199,29 +200,30 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                     .emit();
                 }
 
-                // `typeck_foo_bar` => `foo_bar` (in `typeck.ftl`)
-                // `const_eval_baz` => `baz` (in `const_eval.ftl`)
+                // Require that the message name starts with the crate name
+                // `hir_typeck_foo_bar` (in `hir_typeck.ftl`)
+                // `const_eval_baz` (in `const_eval.ftl`)
                 // `const-eval-hyphen-having` => `hyphen_having` (in `const_eval.ftl`)
                 // The last case we error about above, but we want to fall back gracefully
                 // so that only the error is being emitted and not also one about the macro
                 // failing.
-                let crate_prefix = format!("{}_", res.ident);
+                let crate_prefix = format!("{}_", res.krate);
 
                 let snake_name = name.replace('-', "_");
-                let snake_name = match snake_name.strip_prefix(&crate_prefix) {
-                    Some(rest) => Ident::new(rest, span),
-                    None => {
-                        Diagnostic::spanned(
-                            path_span,
-                            Level::Error,
-                            format!("name `{name}` does not start with the crate name"),
-                        )
-                        .help(format!("prepend `{crate_prefix}` to the slug name: `{crate_prefix}{snake_name}`"))
-                        .emit();
-                        Ident::new(&snake_name, span)
-                    }
+                if !snake_name.starts_with(&crate_prefix) {
+                    Diagnostic::spanned(
+                        path_span,
+                        Level::Error,
+                        format!("name `{name}` does not start with the crate name"),
+                    )
+                    .help(format!(
+                        "prepend `{crate_prefix}` to the slug name: `{crate_prefix}{snake_name}`"
+                    ))
+                    .emit();
                 };
 
+                let snake_name = Ident::new(&snake_name, span);
+
                 constants.extend(quote! {
                     pub const #snake_name: crate::DiagnosticMessage =
                         crate::DiagnosticMessage::FluentIdentifier(
@@ -275,12 +277,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
 
         includes.extend(quote! { include_str!(#relative_ftl_path), });
 
-        let ident = res.ident;
-        generated.extend(quote! {
-            pub mod #ident {
-                #constants
-            }
-        });
+        generated.extend(constants);
     }
 
     quote! {
diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs
index f98cc66e9e9..78df0cd1d34 100644
--- a/compiler/rustc_macros/src/diagnostics/mod.rs
+++ b/compiler/rustc_macros/src/diagnostics/mod.rs
@@ -23,14 +23,14 @@ use synstructure::Structure;
 /// # extern crate rust_middle;
 /// # use rustc_middle::ty::Ty;
 /// #[derive(Diagnostic)]
-/// #[diag(borrowck::move_out_of_borrow, code = "E0505")]
+/// #[diag(borrowck_move_out_of_borrow, code = "E0505")]
 /// pub struct MoveOutOfBorrowError<'tcx> {
 ///     pub name: Ident,
 ///     pub ty: Ty<'tcx>,
 ///     #[primary_span]
 ///     #[label]
 ///     pub span: Span,
-///     #[label(borrowck::first_borrow_label)]
+///     #[label(first_borrow_label)]
 ///     pub first_borrow_span: Span,
 ///     #[suggestion(code = "{name}.clone()")]
 ///     pub clone_sugg: Option<(Span, Applicability)>
@@ -67,14 +67,14 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream {
 ///
 /// ```ignore (rust)
 /// #[derive(LintDiagnostic)]
-/// #[diag(lint::atomic_ordering_invalid_fail_success)]
+/// #[diag(lint_atomic_ordering_invalid_fail_success)]
 /// pub struct AtomicOrderingInvalidLint {
 ///     method: Symbol,
 ///     success_ordering: Symbol,
 ///     fail_ordering: Symbol,
-///     #[label(lint::fail_label)]
+///     #[label(fail_label)]
 ///     fail_order_arg_span: Span,
-///     #[label(lint::success_label)]
+///     #[label(success_label)]
 ///     #[suggestion(
 ///         code = "std::sync::atomic::Ordering::{success_suggestion}",
 ///         applicability = "maybe-incorrect"
@@ -115,12 +115,12 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
 /// ```ignore (rust)
 /// #[derive(Subdiagnostic)]
 /// pub enum ExpectedIdentifierLabel<'tcx> {
-///     #[label(parser::expected_identifier)]
+///     #[label(expected_identifier)]
 ///     WithoutFound {
 ///         #[primary_span]
 ///         span: Span,
 ///     }
-///     #[label(parser::expected_identifier_found)]
+///     #[label(expected_identifier_found)]
 ///     WithFound {
 ///         #[primary_span]
 ///         span: Span,
@@ -129,7 +129,7 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
 /// }
 ///
 /// #[derive(Subdiagnostic)]
-/// #[suggestion_verbose(parser::raw_identifier)]
+/// #[suggestion(style = "verbose",parser::raw_identifier)]
 /// pub struct RawIdentifierSuggestion<'tcx> {
 ///     #[primary_span]
 ///     span: Span,
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 3d4c3ab9fd7..fa0ca5a5242 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -5,15 +5,17 @@ use crate::diagnostics::error::{
     DiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
-    build_field_mapping, new_code_ident, report_error_if_not_applied_to_applicability,
-    report_error_if_not_applied_to_span, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce,
-    SpannedOption, SubdiagnosticKind,
+    build_field_mapping, is_doc_comment, new_code_ident,
+    report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, FieldInfo,
+    FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
 };
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote};
-use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path};
+use syn::{spanned::Spanned, Attribute, Meta, MetaList, NestedMeta, Path};
 use synstructure::{BindingInfo, Structure, VariantInfo};
 
+use super::utils::{build_suggestion_code, AllowMultipleAlternatives};
+
 /// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
 pub(crate) struct SubdiagnosticDeriveBuilder {
     diag: syn::Ident,
@@ -41,8 +43,14 @@ impl SubdiagnosticDeriveBuilder {
                 }
             }
 
-            if matches!(ast.data, syn::Data::Enum(..)) {
+            let is_enum = matches!(ast.data, syn::Data::Enum(..));
+            if is_enum {
                 for attr in &ast.attrs {
+                    // Always allow documentation comments.
+                    if is_doc_comment(attr) {
+                        continue;
+                    }
+
                     span_err(
                         attr.span().unwrap(),
                         "unsupported type attribute for subdiagnostic enum",
@@ -62,6 +70,7 @@ impl SubdiagnosticDeriveBuilder {
                     span_field: None,
                     applicability: None,
                     has_suggestion_parts: false,
+                    is_enum,
                 };
                 builder.into_tokens().unwrap_or_else(|v| v.to_compile_error())
             });
@@ -79,7 +88,7 @@ impl SubdiagnosticDeriveBuilder {
             gen impl rustc_errors::AddToDiagnostic for @Self {
                 fn add_to_diagnostic_with<__F>(self, #diag: &mut rustc_errors::Diagnostic, #f: __F)
                 where
-                    __F: Fn(
+                    __F: core::ops::Fn(
                         &mut rustc_errors::Diagnostic,
                         rustc_errors::SubdiagnosticMessage
                     ) -> rustc_errors::SubdiagnosticMessage,
@@ -122,6 +131,9 @@ struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
     /// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error
     /// during finalization if still `false`.
     has_suggestion_parts: bool,
+
+    /// Set to true when this variant is an enum variant rather than just the body of a struct.
+    is_enum: bool,
 }
 
 impl<'parent, 'a> HasFieldMap for SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
@@ -173,7 +185,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
         let mut kind_slugs = vec![];
 
         for attr in self.variant.ast().attrs {
-            let (kind, slug) = SubdiagnosticKind::from_attr(attr, self)?;
+            let Some((kind, slug)) = SubdiagnosticKind::from_attr(attr, self)? else {
+                // Some attributes aren't errors - like documentation comments - but also aren't
+                // subdiagnostics.
+                continue;
+            };
 
             let Some(slug) = slug else {
                 let name = attr.path.segments.last().unwrap().ident.to_string();
@@ -227,6 +243,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
         ast.attrs
             .iter()
             .map(|attr| {
+                // Always allow documentation comments.
+                if is_doc_comment(attr) {
+                    return quote! {};
+                }
+
                 let info = FieldInfo {
                     binding,
                     ty: inner_ty.inner_type().unwrap_or(&ast.ty),
@@ -290,6 +311,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
                     report_error_if_not_applied_to_span(attr, &info)?;
 
                     let binding = info.binding.binding.clone();
+                    // FIXME(#100717): support `Option<Span>` on `primary_span` like in the
+                    // diagnostic derive
                     self.span_field.set_once(binding, span);
                 }
 
@@ -393,15 +416,16 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
                     let nested_name = meta.path().segments.last().unwrap().ident.to_string();
                     let nested_name = nested_name.as_str();
 
-                    let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) = meta else {
-                        throw_invalid_nested_attr!(attr, &nested_attr);
-                    };
-
                     match nested_name {
                         "code" => {
-                            let formatted_str = self.build_format(&value.value(), value.span());
                             let code_field = new_code_ident();
-                            code.set_once((code_field, formatted_str), span);
+                            let formatting_init = build_suggestion_code(
+                                &code_field,
+                                meta,
+                                self,
+                                AllowMultipleAlternatives::No,
+                            );
+                            code.set_once((code_field, formatting_init), span);
                         }
                         _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
                             diag.help("`code` is the only valid nested attribute")
@@ -409,14 +433,14 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
                     }
                 }
 
-                let Some((code_field, formatted_str)) = code.value() else {
+                let Some((code_field, formatting_init)) = code.value() else {
                     span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
                         .emit();
                     return Ok(quote! {});
                 };
                 let binding = info.binding;
 
-                self.formatting_init.extend(quote! { let #code_field = #formatted_str; });
+                self.formatting_init.extend(formatting_init);
                 let code_field = if clone_suggestion_code {
                     quote! { #code_field.clone() }
                 } else {
@@ -443,10 +467,16 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
     pub fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
         let kind_slugs = self.identify_kind()?;
         if kind_slugs.is_empty() {
-            throw_span_err!(
-                self.variant.ast().ident.span().unwrap(),
-                "subdiagnostic kind not specified"
-            );
+            if self.is_enum {
+                // It's okay for a variant to not be a subdiagnostic at all..
+                return Ok(quote! {});
+            } else {
+                // ..but structs should always be _something_.
+                throw_span_err!(
+                    self.variant.ast().ident.span().unwrap(),
+                    "subdiagnostic kind not specified"
+                );
+            }
         };
 
         let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect();
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 4fd4adc5112..ba06f61299f 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -2,7 +2,7 @@ use crate::diagnostics::error::{
     span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError,
 };
 use proc_macro::Span;
-use proc_macro2::TokenStream;
+use proc_macro2::{Ident, TokenStream};
 use quote::{format_ident, quote, ToTokens};
 use std::cell::RefCell;
 use std::collections::{BTreeSet, HashMap};
@@ -12,7 +12,7 @@ use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple};
 use syn::{MetaList, MetaNameValue, NestedMeta, Path};
 use synstructure::{BindingInfo, VariantInfo};
 
-use super::error::invalid_nested_attr;
+use super::error::{invalid_attr, invalid_nested_attr};
 
 thread_local! {
     pub static CODE_IDENT_COUNT: RefCell<u32> = RefCell::new(0);
@@ -395,17 +395,90 @@ pub(super) fn build_field_mapping<'v>(variant: &VariantInfo<'v>) -> HashMap<Stri
     fields_map
 }
 
+#[derive(Copy, Clone, Debug)]
+pub(super) enum AllowMultipleAlternatives {
+    No,
+    Yes,
+}
+
+/// Constructs the `format!()` invocation(s) necessary for a `#[suggestion*(code = "foo")]` or
+/// `#[suggestion*(code("foo", "bar"))]` attribute field
+pub(super) fn build_suggestion_code(
+    code_field: &Ident,
+    meta: &Meta,
+    fields: &impl HasFieldMap,
+    allow_multiple: AllowMultipleAlternatives,
+) -> TokenStream {
+    let values = match meta {
+        // `code = "foo"`
+        Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => vec![s],
+        // `code("foo", "bar")`
+        Meta::List(MetaList { nested, .. }) => {
+            if let AllowMultipleAlternatives::No = allow_multiple {
+                span_err(
+                    meta.span().unwrap(),
+                    "expected exactly one string literal for `code = ...`",
+                )
+                .emit();
+                vec![]
+            } else if nested.is_empty() {
+                span_err(
+                    meta.span().unwrap(),
+                    "expected at least one string literal for `code(...)`",
+                )
+                .emit();
+                vec![]
+            } else {
+                nested
+                    .into_iter()
+                    .filter_map(|item| {
+                        if let NestedMeta::Lit(syn::Lit::Str(s)) = item {
+                            Some(s)
+                        } else {
+                            span_err(
+                                item.span().unwrap(),
+                                "`code(...)` must contain only string literals",
+                            )
+                            .emit();
+                            None
+                        }
+                    })
+                    .collect()
+            }
+        }
+        _ => {
+            span_err(
+                meta.span().unwrap(),
+                r#"`code = "..."`/`code(...)` must contain only string literals"#,
+            )
+            .emit();
+            vec![]
+        }
+    };
+
+    if let AllowMultipleAlternatives::Yes = allow_multiple {
+        let formatted_strings: Vec<_> = values
+            .into_iter()
+            .map(|value| fields.build_format(&value.value(), value.span()))
+            .collect();
+        quote! { let #code_field = [#(#formatted_strings),*].into_iter(); }
+    } else if let [value] = values.as_slice() {
+        let formatted_str = fields.build_format(&value.value(), value.span());
+        quote! { let #code_field = #formatted_str; }
+    } else {
+        // error handled previously
+        quote! { let #code_field = String::new(); }
+    }
+}
+
 /// Possible styles for suggestion subdiagnostics.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
 pub(super) enum SuggestionKind {
-    /// `#[suggestion]`
     Normal,
-    /// `#[suggestion_short]`
     Short,
-    /// `#[suggestion_hidden]`
     Hidden,
-    /// `#[suggestion_verbose]`
     Verbose,
+    ToolOnly,
 }
 
 impl FromStr for SuggestionKind {
@@ -413,15 +486,28 @@ impl FromStr for SuggestionKind {
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         match s {
-            "" => Ok(SuggestionKind::Normal),
-            "_short" => Ok(SuggestionKind::Short),
-            "_hidden" => Ok(SuggestionKind::Hidden),
-            "_verbose" => Ok(SuggestionKind::Verbose),
+            "normal" => Ok(SuggestionKind::Normal),
+            "short" => Ok(SuggestionKind::Short),
+            "hidden" => Ok(SuggestionKind::Hidden),
+            "verbose" => Ok(SuggestionKind::Verbose),
+            "tool-only" => Ok(SuggestionKind::ToolOnly),
             _ => Err(()),
         }
     }
 }
 
+impl fmt::Display for SuggestionKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            SuggestionKind::Normal => write!(f, "normal"),
+            SuggestionKind::Short => write!(f, "short"),
+            SuggestionKind::Hidden => write!(f, "hidden"),
+            SuggestionKind::Verbose => write!(f, "verbose"),
+            SuggestionKind::ToolOnly => write!(f, "tool-only"),
+        }
+    }
+}
+
 impl SuggestionKind {
     pub fn to_suggestion_style(&self) -> TokenStream {
         match self {
@@ -437,6 +523,19 @@ impl SuggestionKind {
             SuggestionKind::Verbose => {
                 quote! { rustc_errors::SuggestionStyle::ShowAlways }
             }
+            SuggestionKind::ToolOnly => {
+                quote! { rustc_errors::SuggestionStyle::CompletelyHidden }
+            }
+        }
+    }
+
+    fn from_suffix(s: &str) -> Option<Self> {
+        match s {
+            "" => Some(SuggestionKind::Normal),
+            "_short" => Some(SuggestionKind::Short),
+            "_hidden" => Some(SuggestionKind::Hidden),
+            "_verbose" => Some(SuggestionKind::Verbose),
+            _ => None,
         }
     }
 }
@@ -477,32 +576,61 @@ impl SubdiagnosticKind {
     pub(super) fn from_attr(
         attr: &Attribute,
         fields: &impl HasFieldMap,
-    ) -> Result<(SubdiagnosticKind, Option<Path>), DiagnosticDeriveError> {
+    ) -> Result<Option<(SubdiagnosticKind, Option<Path>)>, DiagnosticDeriveError> {
+        // Always allow documentation comments.
+        if is_doc_comment(attr) {
+            return Ok(None);
+        }
+
         let span = attr.span().unwrap();
 
         let name = attr.path.segments.last().unwrap().ident.to_string();
         let name = name.as_str();
 
         let meta = attr.parse_meta()?;
+
         let mut kind = match name {
             "label" => SubdiagnosticKind::Label,
             "note" => SubdiagnosticKind::Note,
             "help" => SubdiagnosticKind::Help,
             "warning" => SubdiagnosticKind::Warn,
             _ => {
+                // Recover old `#[(multipart_)suggestion_*]` syntaxes
+                // FIXME(#100717): remove
                 if let Some(suggestion_kind) =
-                    name.strip_prefix("suggestion").and_then(|s| s.parse().ok())
+                    name.strip_prefix("suggestion").and_then(SuggestionKind::from_suffix)
                 {
+                    if suggestion_kind != SuggestionKind::Normal {
+                        invalid_attr(attr, &meta)
+                            .help(format!(
+                                r#"Use `#[suggestion(..., style = "{}")]` instead"#,
+                                suggestion_kind
+                            ))
+                            .emit();
+                    }
+
                     SubdiagnosticKind::Suggestion {
-                        suggestion_kind,
+                        suggestion_kind: SuggestionKind::Normal,
                         applicability: None,
                         code_field: new_code_ident(),
                         code_init: TokenStream::new(),
                     }
                 } else if let Some(suggestion_kind) =
-                    name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
+                    name.strip_prefix("multipart_suggestion").and_then(SuggestionKind::from_suffix)
                 {
-                    SubdiagnosticKind::MultipartSuggestion { suggestion_kind, applicability: None }
+                    if suggestion_kind != SuggestionKind::Normal {
+                        invalid_attr(attr, &meta)
+                            .help(format!(
+                                r#"Use `#[multipart_suggestion(..., style = "{}")]` instead"#,
+                                suggestion_kind
+                            ))
+                            .emit();
+                    }
+
+                    SubdiagnosticKind::MultipartSuggestion {
+                        suggestion_kind: SuggestionKind::Normal,
+                        applicability: None,
+                    }
                 } else {
                     throw_invalid_attr!(attr, &meta);
                 }
@@ -526,7 +654,9 @@ impl SubdiagnosticKind {
                     | SubdiagnosticKind::Note
                     | SubdiagnosticKind::Help
                     | SubdiagnosticKind::Warn
-                    | SubdiagnosticKind::MultipartSuggestion { .. } => return Ok((kind, None)),
+                    | SubdiagnosticKind::MultipartSuggestion { .. } => {
+                        return Ok(Some((kind, None)));
+                    }
                     SubdiagnosticKind::Suggestion { .. } => {
                         throw_span_err!(span, "suggestion without `code = \"...\"`")
                     }
@@ -538,6 +668,7 @@ impl SubdiagnosticKind {
         };
 
         let mut code = None;
+        let mut suggestion_kind = None;
 
         let mut nested_iter = nested.into_iter().peekable();
 
@@ -564,21 +695,23 @@ impl SubdiagnosticKind {
             let nested_name = meta.path().segments.last().unwrap().ident.to_string();
             let nested_name = nested_name.as_str();
 
-            let value = match meta {
-                Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => value,
+            let string_value = match meta {
+                Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => Some(value),
+
                 Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
                     diag.help("a diagnostic slug must be the first argument to the attribute")
                 }),
-                _ => {
-                    invalid_nested_attr(attr, &nested_attr).emit();
-                    continue;
-                }
+                _ => None,
             };
 
             match (nested_name, &mut kind) {
                 ("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
-                    let formatted_str = fields.build_format(&value.value(), value.span());
-                    let code_init = quote! { let #code_field = #formatted_str; };
+                    let code_init = build_suggestion_code(
+                        code_field,
+                        meta,
+                        fields,
+                        AllowMultipleAlternatives::Yes,
+                    );
                     code.set_once(code_init, span);
                 }
                 (
@@ -586,22 +719,48 @@ impl SubdiagnosticKind {
                     SubdiagnosticKind::Suggestion { ref mut applicability, .. }
                     | SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. },
                 ) => {
+                    let Some(value) = string_value else {
+                        invalid_nested_attr(attr, &nested_attr).emit();
+                        continue;
+                    };
+
                     let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| {
                         span_err(span, "invalid applicability").emit();
                         Applicability::Unspecified
                     });
                     applicability.set_once(value, span);
                 }
+                (
+                    "style",
+                    SubdiagnosticKind::Suggestion { .. }
+                    | SubdiagnosticKind::MultipartSuggestion { .. },
+                ) => {
+                    let Some(value) = string_value else {
+                        invalid_nested_attr(attr, &nested_attr).emit();
+                        continue;
+                    };
+
+                    let value = value.value().parse().unwrap_or_else(|()| {
+                        span_err(value.span().unwrap(), "invalid suggestion style")
+                            .help("valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`")
+                            .emit();
+                        SuggestionKind::Normal
+                    });
+
+                    suggestion_kind.set_once(value, span);
+                }
 
                 // Invalid nested attribute
                 (_, SubdiagnosticKind::Suggestion { .. }) => {
                     invalid_nested_attr(attr, &nested_attr)
-                        .help("only `code` and `applicability` are valid nested attributes")
+                        .help(
+                            "only `style`, `code` and `applicability` are valid nested attributes",
+                        )
                         .emit();
                 }
                 (_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
                     invalid_nested_attr(attr, &nested_attr)
-                        .help("only `applicability` is a valid nested attributes")
+                        .help("only `style` and `applicability` are valid nested attributes")
                         .emit()
                 }
                 _ => {
@@ -611,22 +770,37 @@ impl SubdiagnosticKind {
         }
 
         match kind {
-            SubdiagnosticKind::Suggestion { ref code_field, ref mut code_init, .. } => {
+            SubdiagnosticKind::Suggestion {
+                ref code_field,
+                ref mut code_init,
+                suggestion_kind: ref mut kind_field,
+                ..
+            } => {
+                if let Some(kind) = suggestion_kind.value() {
+                    *kind_field = kind;
+                }
+
                 *code_init = if let Some(init) = code.value() {
                     init
                 } else {
                     span_err(span, "suggestion without `code = \"...\"`").emit();
-                    quote! { let #code_field: String = unreachable!(); }
+                    quote! { let #code_field = std::iter::empty(); }
                 };
             }
+            SubdiagnosticKind::MultipartSuggestion {
+                suggestion_kind: ref mut kind_field, ..
+            } => {
+                if let Some(kind) = suggestion_kind.value() {
+                    *kind_field = kind;
+                }
+            }
             SubdiagnosticKind::Label
             | SubdiagnosticKind::Note
             | SubdiagnosticKind::Help
-            | SubdiagnosticKind::Warn
-            | SubdiagnosticKind::MultipartSuggestion { .. } => {}
+            | SubdiagnosticKind::Warn => {}
         }
 
-        Ok((kind, slug))
+        Ok(Some((kind, slug)))
     }
 }
 
@@ -637,7 +811,7 @@ impl quote::IdentFragment for SubdiagnosticKind {
             SubdiagnosticKind::Note => write!(f, "note"),
             SubdiagnosticKind::Help => write!(f, "help"),
             SubdiagnosticKind::Warn => write!(f, "warn"),
-            SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"),
+            SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestions_with_style"),
             SubdiagnosticKind::MultipartSuggestion { .. } => {
                 write!(f, "multipart_suggestion_with_style")
             }
@@ -654,3 +828,7 @@ impl quote::IdentFragment for SubdiagnosticKind {
 pub(super) fn should_generate_set_arg(field: &Field) -> bool {
     field.attrs.is_empty()
 }
+
+pub(super) fn is_doc_comment(attr: &Attribute) -> bool {
+    attr.path.segments.last().unwrap().ident.to_string() == "doc"
+}
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index d49926c90ca..7cefafef9d9 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -237,27 +237,32 @@ fn doc_comment_from_desc(list: &Punctuated<Expr, token::Comma>) -> Result<Attrib
 }
 
 /// Add the impl of QueryDescription for the query to `impls` if one is requested
-fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStream) {
-    let name = &query.name;
-    let key = &query.key;
-    let modifiers = &query.modifiers;
+fn add_query_desc_cached_impl(
+    query: &Query,
+    descs: &mut proc_macro2::TokenStream,
+    cached: &mut proc_macro2::TokenStream,
+) {
+    let Query { name, key, modifiers, .. } = &query;
 
     // Find out if we should cache the query on disk
     let cache = if let Some((args, expr)) = modifiers.cache.as_ref() {
         let tcx = args.as_ref().map(|t| quote! { #t }).unwrap_or_else(|| quote! { _ });
         // expr is a `Block`, meaning that `{ #expr }` gets expanded
         // to `{ { stmts... } }`, which triggers the `unused_braces` lint.
+        // we're taking `key` by reference, but some rustc types usually prefer being passed by value
         quote! {
-            #[allow(unused_variables, unused_braces)]
+            #[allow(unused_variables, unused_braces, rustc::pass_by_value)]
             #[inline]
-            fn cache_on_disk(#tcx: TyCtxt<'tcx>, #key: &Self::Key) -> bool {
+            pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::ty::query::query_keys::#name<'tcx>) -> bool {
                 #expr
             }
         }
     } else {
         quote! {
+            // we're taking `key` by reference, but some rustc types usually prefer being passed by value
+            #[allow(rustc::pass_by_value)]
             #[inline]
-            fn cache_on_disk(_: TyCtxt<'tcx>, _: &Self::Key) -> bool {
+            pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::ty::query::query_keys::#name<'tcx>) -> bool {
                 false
             }
         }
@@ -268,19 +273,20 @@ fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStrea
 
     let desc = quote! {
         #[allow(unused_variables)]
-        fn describe(tcx: QueryCtxt<'tcx>, key: Self::Key) -> String {
-            let (#tcx, #key) = (*tcx, key);
+        pub fn #name<'tcx>(tcx: TyCtxt<'tcx>, key: crate::ty::query::query_keys::#name<'tcx>) -> String {
+            let (#tcx, #key) = (tcx, key);
             ::rustc_middle::ty::print::with_no_trimmed_paths!(
                 format!(#desc)
             )
         }
     };
 
-    impls.extend(quote! {
-        (#name) => {
-            #desc
-            #cache
-        };
+    descs.extend(quote! {
+        #desc
+    });
+
+    cached.extend(quote! {
+        #cache
     });
 }
 
@@ -289,7 +295,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
 
     let mut query_stream = quote! {};
     let mut query_description_stream = quote! {};
-    let mut cached_queries = quote! {};
+    let mut query_cached_stream = quote! {};
 
     for query in queries.0 {
         let Query { name, arg, modifiers, .. } = &query;
@@ -299,12 +305,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
             _ => quote! { #result_full },
         };
 
-        if modifiers.cache.is_some() {
-            cached_queries.extend(quote! {
-                #name,
-            });
-        }
-
         let mut attributes = Vec::new();
 
         macro_rules! passthrough {
@@ -350,7 +350,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
             [#attribute_stream] fn #name(#arg) #result,
         });
 
-        add_query_description_impl(&query, &mut query_description_stream);
+        add_query_desc_cached_impl(&query, &mut query_description_stream, &mut query_cached_stream);
     }
 
     TokenStream::from(quote! {
@@ -364,9 +364,13 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
             }
         }
 
-        #[macro_export]
-        macro_rules! rustc_query_description {
+        pub mod descs {
+            use super::*;
             #query_description_stream
         }
+        pub mod cached {
+            use super::*;
+            #query_cached_stream
+        }
     })
 }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index cfcceecbef4..d4c457975a8 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -1,8 +1,10 @@
 //! Validates all used crates and extern libraries and loads their metadata
 
 use crate::errors::{
-    ConflictingGlobalAlloc, CrateNotPanicRuntime, GlobalAllocRequired, NoMultipleGlobalAlloc,
-    NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime, ProfilerBuiltinsNeedsCore,
+    AllocFuncRequired, ConflictingAllocErrorHandler, ConflictingGlobalAlloc, CrateNotPanicRuntime,
+    GlobalAllocRequired, MissingAllocErrorHandler, NoMultipleAllocErrorHandler,
+    NoMultipleGlobalAlloc, NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime,
+    ProfilerBuiltinsNeedsCore,
 };
 use crate::locator::{CrateError, CrateLocator, CratePaths};
 use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
@@ -41,8 +43,13 @@ pub struct CStore {
     /// This crate needs an allocator and either provides it itself, or finds it in a dependency.
     /// If the above is true, then this field denotes the kind of the found allocator.
     allocator_kind: Option<AllocatorKind>,
+    /// This crate needs an allocation error handler and either provides it itself, or finds it in a dependency.
+    /// If the above is true, then this field denotes the kind of the found allocator.
+    alloc_error_handler_kind: Option<AllocatorKind>,
     /// This crate has a `#[global_allocator]` item.
     has_global_allocator: bool,
+    /// This crate has a `#[alloc_error_handler]` item.
+    has_alloc_error_handler: bool,
 
     /// This map is used to verify we get no hash conflicts between
     /// `StableCrateId` values.
@@ -197,10 +204,18 @@ impl CStore {
         self.allocator_kind
     }
 
+    pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> {
+        self.alloc_error_handler_kind
+    }
+
     pub(crate) fn has_global_allocator(&self) -> bool {
         self.has_global_allocator
     }
 
+    pub(crate) fn has_alloc_error_handler(&self) -> bool {
+        self.has_alloc_error_handler
+    }
+
     pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
         let json_unused_externs = tcx.sess.opts.json_unused_externs;
 
@@ -247,7 +262,9 @@ impl<'a> CrateLoader<'a> {
                 metas: IndexVec::from_elem_n(None, 1),
                 injected_panic_runtime: None,
                 allocator_kind: None,
+                alloc_error_handler_kind: None,
                 has_global_allocator: false,
+                has_alloc_error_handler: false,
                 stable_crate_ids,
                 unused_externs: Vec::new(),
             },
@@ -792,6 +809,13 @@ impl<'a> CrateLoader<'a> {
             }
             spans => !spans.is_empty(),
         };
+        self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(&self.sess, krate) {
+            [span1, span2, ..] => {
+                self.sess.emit_err(NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
+                true
+            }
+            spans => !spans.is_empty(),
+        };
 
         // Check to see if we actually need an allocator. This desire comes
         // about through the `#![needs_allocator]` attribute and is typically
@@ -832,22 +856,48 @@ impl<'a> CrateLoader<'a> {
                 }
             }
         }
+        let mut alloc_error_handler =
+            self.cstore.has_alloc_error_handler.then(|| Symbol::intern("this crate"));
+        for (_, data) in self.cstore.iter_crate_data() {
+            if data.has_alloc_error_handler() {
+                match alloc_error_handler {
+                    Some(other_crate) => {
+                        self.sess.emit_err(ConflictingAllocErrorHandler {
+                            crate_name: data.name(),
+                            other_crate_name: other_crate,
+                        });
+                    }
+                    None => alloc_error_handler = Some(data.name()),
+                }
+            }
+        }
 
         if global_allocator.is_some() {
             self.cstore.allocator_kind = Some(AllocatorKind::Global);
-            return;
+        } else {
+            // Ok we haven't found a global allocator but we still need an
+            // allocator. At this point our allocator request is typically fulfilled
+            // by the standard library, denoted by the `#![default_lib_allocator]`
+            // attribute.
+            if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
+                && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
+            {
+                self.sess.emit_err(GlobalAllocRequired);
+            }
+            self.cstore.allocator_kind = Some(AllocatorKind::Default);
         }
 
-        // Ok we haven't found a global allocator but we still need an
-        // allocator. At this point our allocator request is typically fulfilled
-        // by the standard library, denoted by the `#![default_lib_allocator]`
-        // attribute.
-        if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
-            && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
-        {
-            self.sess.emit_err(GlobalAllocRequired);
+        if alloc_error_handler.is_some() {
+            self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global);
+        } else {
+            // The alloc crate provides a default allocation error handler if
+            // one isn't specified.
+            if !self.sess.features_untracked().default_alloc_error_handler {
+                self.sess.emit_err(AllocFuncRequired);
+                self.sess.emit_note(MissingAllocErrorHandler);
+            }
+            self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default);
         }
-        self.cstore.allocator_kind = Some(AllocatorKind::Default);
     }
 
     fn inject_dependency_if(
@@ -1023,3 +1073,26 @@ fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
     visit::walk_crate(&mut f, krate);
     f.spans
 }
+
+fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
+    struct Finder<'a> {
+        sess: &'a Session,
+        name: Symbol,
+        spans: Vec<Span>,
+    }
+    impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> {
+        fn visit_item(&mut self, item: &'ast ast::Item) {
+            if item.ident.name == self.name
+                && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol)
+            {
+                self.spans.push(item.span);
+            }
+            visit::walk_item(self, item)
+        }
+    }
+
+    let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom));
+    let mut f = Finder { sess, name, spans: Vec::new() };
+    visit::walk_crate(&mut f, krate);
+    f.spans
+}
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index 1cd550644bf..e5b91d566e5 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -12,41 +12,41 @@ use rustc_target::spec::{PanicStrategy, TargetTriple};
 use crate::locator::CrateFlavor;
 
 #[derive(Diagnostic)]
-#[diag(metadata::rlib_required)]
+#[diag(metadata_rlib_required)]
 pub struct RlibRequired {
     pub crate_name: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::lib_required)]
+#[diag(metadata_lib_required)]
 pub struct LibRequired<'a> {
     pub crate_name: Symbol,
     pub kind: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::crate_dep_multiple)]
+#[diag(metadata_crate_dep_multiple)]
 #[help]
 pub struct CrateDepMultiple {
     pub crate_name: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::two_panic_runtimes)]
+#[diag(metadata_two_panic_runtimes)]
 pub struct TwoPanicRuntimes {
     pub prev_name: Symbol,
     pub cur_name: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::bad_panic_strategy)]
+#[diag(metadata_bad_panic_strategy)]
 pub struct BadPanicStrategy {
     pub runtime: Symbol,
     pub strategy: PanicStrategy,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::required_panic_strategy)]
+#[diag(metadata_required_panic_strategy)]
 pub struct RequiredPanicStrategy {
     pub crate_name: Symbol,
     pub found_strategy: PanicStrategy,
@@ -54,7 +54,7 @@ pub struct RequiredPanicStrategy {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::incompatible_panic_in_drop_strategy)]
+#[diag(metadata_incompatible_panic_in_drop_strategy)]
 pub struct IncompatiblePanicInDropStrategy {
     pub crate_name: Symbol,
     pub found_strategy: PanicStrategy,
@@ -62,56 +62,56 @@ pub struct IncompatiblePanicInDropStrategy {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_names_in_link)]
+#[diag(metadata_multiple_names_in_link)]
 pub struct MultipleNamesInLink {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_kinds_in_link)]
+#[diag(metadata_multiple_kinds_in_link)]
 pub struct MultipleKindsInLink {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_name_form)]
+#[diag(metadata_link_name_form)]
 pub struct LinkNameForm {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_kind_form)]
+#[diag(metadata_link_kind_form)]
 pub struct LinkKindForm {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_modifiers_form)]
+#[diag(metadata_link_modifiers_form)]
 pub struct LinkModifiersForm {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_cfg_form)]
+#[diag(metadata_link_cfg_form)]
 pub struct LinkCfgForm {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::wasm_import_form)]
+#[diag(metadata_wasm_import_form)]
 pub struct WasmImportForm {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::empty_link_name, code = "E0454")]
+#[diag(metadata_empty_link_name, code = "E0454")]
 pub struct EmptyLinkName {
     #[primary_span]
     #[label]
@@ -119,21 +119,21 @@ pub struct EmptyLinkName {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_framework_apple, code = "E0455")]
+#[diag(metadata_link_framework_apple, code = "E0455")]
 pub struct LinkFrameworkApple {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::framework_only_windows, code = "E0455")]
+#[diag(metadata_framework_only_windows, code = "E0455")]
 pub struct FrameworkOnlyWindows {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::unknown_link_kind, code = "E0458")]
+#[diag(metadata_unknown_link_kind, code = "E0458")]
 pub struct UnknownLinkKind<'a> {
     #[primary_span]
     #[label]
@@ -142,49 +142,49 @@ pub struct UnknownLinkKind<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_link_modifiers)]
+#[diag(metadata_multiple_link_modifiers)]
 pub struct MultipleLinkModifiers {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_cfgs)]
+#[diag(metadata_multiple_cfgs)]
 pub struct MultipleCfgs {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_cfg_single_predicate)]
+#[diag(metadata_link_cfg_single_predicate)]
 pub struct LinkCfgSinglePredicate {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_wasm_import)]
+#[diag(metadata_multiple_wasm_import)]
 pub struct MultipleWasmImport {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::unexpected_link_arg)]
+#[diag(metadata_unexpected_link_arg)]
 pub struct UnexpectedLinkArg {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::invalid_link_modifier)]
+#[diag(metadata_invalid_link_modifier)]
 pub struct InvalidLinkModifier {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_modifiers)]
+#[diag(metadata_multiple_modifiers)]
 pub struct MultipleModifiers<'a> {
     #[primary_span]
     pub span: Span,
@@ -192,28 +192,28 @@ pub struct MultipleModifiers<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::bundle_needs_static)]
+#[diag(metadata_bundle_needs_static)]
 pub struct BundleNeedsStatic {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::whole_archive_needs_static)]
+#[diag(metadata_whole_archive_needs_static)]
 pub struct WholeArchiveNeedsStatic {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::as_needed_compatibility)]
+#[diag(metadata_as_needed_compatibility)]
 pub struct AsNeededCompatibility {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::unknown_link_modifier)]
+#[diag(metadata_unknown_link_modifier)]
 pub struct UnknownLinkModifier<'a> {
     #[primary_span]
     pub span: Span,
@@ -221,14 +221,14 @@ pub struct UnknownLinkModifier<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::incompatible_wasm_link)]
+#[diag(metadata_incompatible_wasm_link)]
 pub struct IncompatibleWasmLink {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_requires_name, code = "E0459")]
+#[diag(metadata_link_requires_name, code = "E0459")]
 pub struct LinkRequiresName {
     #[primary_span]
     #[label]
@@ -236,126 +236,151 @@ pub struct LinkRequiresName {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::raw_dylib_no_nul)]
+#[diag(metadata_raw_dylib_no_nul)]
 pub struct RawDylibNoNul {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_ordinal_raw_dylib)]
+#[diag(metadata_link_ordinal_raw_dylib)]
 pub struct LinkOrdinalRawDylib {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::lib_framework_apple)]
+#[diag(metadata_lib_framework_apple)]
 pub struct LibFrameworkApple;
 
 #[derive(Diagnostic)]
-#[diag(metadata::empty_renaming_target)]
+#[diag(metadata_empty_renaming_target)]
 pub struct EmptyRenamingTarget<'a> {
     pub lib_name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::renaming_no_link)]
+#[diag(metadata_renaming_no_link)]
 pub struct RenamingNoLink<'a> {
     pub lib_name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_renamings)]
+#[diag(metadata_multiple_renamings)]
 pub struct MultipleRenamings<'a> {
     pub lib_name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::no_link_mod_override)]
+#[diag(metadata_no_link_mod_override)]
 pub struct NoLinkModOverride {
     #[primary_span]
     pub span: Option<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::unsupported_abi_i686)]
+#[diag(metadata_unsupported_abi_i686)]
 pub struct UnsupportedAbiI686 {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::unsupported_abi)]
+#[diag(metadata_unsupported_abi)]
 pub struct UnsupportedAbi {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::fail_create_file_encoder)]
+#[diag(metadata_fail_create_file_encoder)]
 pub struct FailCreateFileEncoder {
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::fail_seek_file)]
+#[diag(metadata_fail_seek_file)]
 pub struct FailSeekFile {
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::fail_write_file)]
+#[diag(metadata_fail_write_file)]
 pub struct FailWriteFile {
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::crate_not_panic_runtime)]
+#[diag(metadata_crate_not_panic_runtime)]
 pub struct CrateNotPanicRuntime {
     pub crate_name: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::no_panic_strategy)]
+#[diag(metadata_no_panic_strategy)]
 pub struct NoPanicStrategy {
     pub crate_name: Symbol,
     pub strategy: PanicStrategy,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::profiler_builtins_needs_core)]
+#[diag(metadata_profiler_builtins_needs_core)]
 pub struct ProfilerBuiltinsNeedsCore;
 
 #[derive(Diagnostic)]
-#[diag(metadata::not_profiler_runtime)]
+#[diag(metadata_not_profiler_runtime)]
 pub struct NotProfilerRuntime {
     pub crate_name: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::no_multiple_global_alloc)]
+#[diag(metadata_no_multiple_global_alloc)]
 pub struct NoMultipleGlobalAlloc {
     #[primary_span]
     #[label]
     pub span2: Span,
-    #[label(metadata::prev_global_alloc)]
+    #[label(metadata_prev_global_alloc)]
     pub span1: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::conflicting_global_alloc)]
+#[diag(metadata_no_multiple_alloc_error_handler)]
+pub struct NoMultipleAllocErrorHandler {
+    #[primary_span]
+    #[label]
+    pub span2: Span,
+    #[label(metadata_prev_alloc_error_handler)]
+    pub span1: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(metadata_conflicting_global_alloc)]
 pub struct ConflictingGlobalAlloc {
     pub crate_name: Symbol,
     pub other_crate_name: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::global_alloc_required)]
+#[diag(metadata_conflicting_alloc_error_handler)]
+pub struct ConflictingAllocErrorHandler {
+    pub crate_name: Symbol,
+    pub other_crate_name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(metadata_global_alloc_required)]
 pub struct GlobalAllocRequired;
 
 #[derive(Diagnostic)]
-#[diag(metadata::no_transitive_needs_dep)]
+#[diag(metadata_alloc_func_required)]
+pub struct AllocFuncRequired;
+
+#[derive(Diagnostic)]
+#[diag(metadata_missing_alloc_error_handler)]
+pub struct MissingAllocErrorHandler;
+
+#[derive(Diagnostic)]
+#[diag(metadata_no_transitive_needs_dep)]
 pub struct NoTransitiveNeedsDep<'a> {
     pub crate_name: Symbol,
     pub needs_crate_name: &'a str,
@@ -363,39 +388,73 @@ pub struct NoTransitiveNeedsDep<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::failed_write_error)]
+#[diag(metadata_failed_write_error)]
 pub struct FailedWriteError {
     pub filename: PathBuf,
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::missing_native_library)]
+#[diag(metadata_missing_native_library)]
 pub struct MissingNativeLibrary<'a> {
-    pub libname: &'a str,
+    libname: &'a str,
+    #[subdiagnostic]
+    suggest_name: Option<SuggestLibraryName<'a>>,
+}
+
+impl<'a> MissingNativeLibrary<'a> {
+    pub fn new(libname: &'a str, verbatim: bool) -> Self {
+        // if it looks like the user has provided a complete filename rather just the bare lib name,
+        // then provide a note that they might want to try trimming the name
+        let suggested_name = if !verbatim {
+            if let Some(libname) = libname.strip_prefix("lib") && let Some(libname) = libname.strip_suffix(".a") {
+                // this is a unix style filename so trim prefix & suffix
+                Some(libname)
+            } else if let Some(libname) = libname.strip_suffix(".lib") {
+                // this is a Windows style filename so just trim the suffix
+                Some(libname)
+            } else {
+                None
+            }
+        } else {
+            None
+        };
+
+        Self {
+            libname,
+            suggest_name: suggested_name
+                .map(|suggested_name| SuggestLibraryName { suggested_name }),
+        }
+    }
+}
+
+#[derive(Subdiagnostic)]
+#[help(metadata_only_provide_library_name)]
+pub struct SuggestLibraryName<'a> {
+    suggested_name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::failed_create_tempdir)]
+#[diag(metadata_failed_create_tempdir)]
 pub struct FailedCreateTempdir {
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::failed_create_file)]
+#[diag(metadata_failed_create_file)]
 pub struct FailedCreateFile<'a> {
     pub filename: &'a Path,
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::failed_create_encoded_metadata)]
+#[diag(metadata_failed_create_encoded_metadata)]
 pub struct FailedCreateEncodedMetadata {
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::non_ascii_name)]
+#[diag(metadata_non_ascii_name)]
 pub struct NonAsciiName {
     #[primary_span]
     pub span: Span,
@@ -403,7 +462,7 @@ pub struct NonAsciiName {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::extern_location_not_exist)]
+#[diag(metadata_extern_location_not_exist)]
 pub struct ExternLocationNotExist<'a> {
     #[primary_span]
     pub span: Span,
@@ -412,7 +471,7 @@ pub struct ExternLocationNotExist<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::extern_location_not_file)]
+#[diag(metadata_extern_location_not_file)]
 pub struct ExternLocationNotFile<'a> {
     #[primary_span]
     pub span: Span,
@@ -432,7 +491,7 @@ impl IntoDiagnostic<'_> for MultipleCandidates {
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(rustc_errors::fluent::metadata::multiple_candidates);
+        let mut diag = handler.struct_err(rustc_errors::fluent::metadata_multiple_candidates);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("flavor", self.flavor);
         diag.code(error_code!(E0465));
@@ -445,7 +504,7 @@ impl IntoDiagnostic<'_> for MultipleCandidates {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_matching_crates, code = "E0464")]
+#[diag(metadata_multiple_matching_crates, code = "E0464")]
 #[note]
 pub struct MultipleMatchingCrates {
     #[primary_span]
@@ -455,7 +514,7 @@ pub struct MultipleMatchingCrates {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::symbol_conflicts_current, code = "E0519")]
+#[diag(metadata_symbol_conflicts_current, code = "E0519")]
 pub struct SymbolConflictsCurrent {
     #[primary_span]
     pub span: Span,
@@ -463,7 +522,7 @@ pub struct SymbolConflictsCurrent {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::symbol_conflicts_others, code = "E0523")]
+#[diag(metadata_symbol_conflicts_others, code = "E0523")]
 pub struct SymbolConflictsOthers {
     #[primary_span]
     pub span: Span,
@@ -471,7 +530,7 @@ pub struct SymbolConflictsOthers {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::stable_crate_id_collision)]
+#[diag(metadata_stable_crate_id_collision)]
 pub struct StableCrateIdCollision {
     #[primary_span]
     pub span: Span,
@@ -480,7 +539,7 @@ pub struct StableCrateIdCollision {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::dl_error)]
+#[diag(metadata_dl_error)]
 pub struct DlError {
     #[primary_span]
     pub span: Span,
@@ -488,9 +547,9 @@ pub struct DlError {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::newer_crate_version, code = "E0460")]
+#[diag(metadata_newer_crate_version, code = "E0460")]
 #[note]
-#[note(metadata::found_crate_versions)]
+#[note(metadata_found_crate_versions)]
 pub struct NewerCrateVersion {
     #[primary_span]
     pub span: Span,
@@ -500,8 +559,8 @@ pub struct NewerCrateVersion {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::no_crate_with_triple, code = "E0461")]
-#[note(metadata::found_crate_versions)]
+#[diag(metadata_no_crate_with_triple, code = "E0461")]
+#[note(metadata_found_crate_versions)]
 pub struct NoCrateWithTriple<'a> {
     #[primary_span]
     pub span: Span,
@@ -512,8 +571,8 @@ pub struct NoCrateWithTriple<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::found_staticlib, code = "E0462")]
-#[note(metadata::found_crate_versions)]
+#[diag(metadata_found_staticlib, code = "E0462")]
+#[note(metadata_found_crate_versions)]
 #[help]
 pub struct FoundStaticlib {
     #[primary_span]
@@ -524,8 +583,8 @@ pub struct FoundStaticlib {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::incompatible_rustc, code = "E0514")]
-#[note(metadata::found_crate_versions)]
+#[diag(metadata_incompatible_rustc, code = "E0514")]
+#[note(metadata_found_crate_versions)]
 #[help]
 pub struct IncompatibleRustc {
     #[primary_span]
@@ -544,11 +603,12 @@ pub struct InvalidMetadataFiles {
 }
 
 impl IntoDiagnostic<'_> for InvalidMetadataFiles {
+    #[track_caller]
     fn into_diagnostic(
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(rustc_errors::fluent::metadata::invalid_meta_files);
+        let mut diag = handler.struct_err(rustc_errors::fluent::metadata_invalid_meta_files);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("add_info", self.add_info);
         diag.code(error_code!(E0786));
@@ -572,11 +632,12 @@ pub struct CannotFindCrate {
 }
 
 impl IntoDiagnostic<'_> for CannotFindCrate {
+    #[track_caller]
     fn into_diagnostic(
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(rustc_errors::fluent::metadata::cannot_find_crate);
+        let mut diag = handler.struct_err(rustc_errors::fluent::metadata_cannot_find_crate);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("current_crate", self.current_crate);
         diag.set_arg("add_info", self.add_info);
@@ -587,38 +648,38 @@ impl IntoDiagnostic<'_> for CannotFindCrate {
             && self.locator_triple != TargetTriple::from_triple(config::host_triple())
         {
             if self.missing_core {
-                diag.note(rustc_errors::fluent::metadata::target_not_installed);
+                diag.note(rustc_errors::fluent::metadata_target_not_installed);
             } else {
-                diag.note(rustc_errors::fluent::metadata::target_no_std_support);
+                diag.note(rustc_errors::fluent::metadata_target_no_std_support);
             }
             // NOTE: this suggests using rustup, even though the user may not have it installed.
             // That's because they could choose to install it; or this may give them a hint which
             // target they need to install from their distro.
             if self.missing_core {
-                diag.help(rustc_errors::fluent::metadata::consider_downloading_target);
+                diag.help(rustc_errors::fluent::metadata_consider_downloading_target);
             }
             // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway.
             // NOTE: this is a dummy span if `extern crate std` was injected by the compiler.
             // If it's not a dummy, that means someone added `extern crate std` explicitly and
             // `#![no_std]` won't help.
             if !self.missing_core && self.span.is_dummy() {
-                diag.note(rustc_errors::fluent::metadata::std_required);
+                diag.note(rustc_errors::fluent::metadata_std_required);
             }
             if self.is_nightly_build {
-                diag.help(rustc_errors::fluent::metadata::consider_building_std);
+                diag.help(rustc_errors::fluent::metadata_consider_building_std);
             }
         } else if self.crate_name == self.profiler_runtime {
-            diag.note(rustc_errors::fluent::metadata::compiler_missing_profiler);
+            diag.note(rustc_errors::fluent::metadata_compiler_missing_profiler);
         } else if self.crate_name.as_str().starts_with("rustc_") {
-            diag.help(rustc_errors::fluent::metadata::install_missing_components);
+            diag.help(rustc_errors::fluent::metadata_install_missing_components);
         }
-        diag.span_label(self.span, rustc_errors::fluent::metadata::cant_find_crate);
+        diag.span_label(self.span, rustc_errors::fluent::metadata_cant_find_crate);
         diag
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::no_dylib_plugin, code = "E0457")]
+#[diag(metadata_no_dylib_plugin, code = "E0457")]
 pub struct NoDylibPlugin {
     #[primary_span]
     pub span: Span,
@@ -626,7 +687,7 @@ pub struct NoDylibPlugin {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::crate_location_unknown_type)]
+#[diag(metadata_crate_location_unknown_type)]
 pub struct CrateLocationUnknownType<'a> {
     #[primary_span]
     pub span: Span,
@@ -634,7 +695,7 @@ pub struct CrateLocationUnknownType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::lib_filename_form)]
+#[diag(metadata_lib_filename_form)]
 pub struct LibFilenameForm<'a> {
     #[primary_span]
     pub span: Span,
@@ -643,28 +704,28 @@ pub struct LibFilenameForm<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_import_name_type)]
+#[diag(metadata_multiple_import_name_type)]
 pub struct MultipleImportNameType {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::import_name_type_form)]
+#[diag(metadata_import_name_type_form)]
 pub struct ImportNameTypeForm {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::import_name_type_x86)]
+#[diag(metadata_import_name_type_x86)]
 pub struct ImportNameTypeX86 {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::unknown_import_name_type)]
+#[diag(metadata_unknown_import_name_type)]
 pub struct UnknownImportNameType<'a> {
     #[primary_span]
     pub span: Span,
@@ -672,7 +733,7 @@ pub struct UnknownImportNameType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::import_name_type_raw)]
+#[diag(metadata_import_name_type_raw)]
 pub struct ImportNameTypeRaw {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs
index 2ca4cd17fdf..d1c2f3104d0 100644
--- a/compiler/rustc_metadata/src/foreign_modules.rs
+++ b/compiler/rustc_metadata/src/foreign_modules.rs
@@ -6,13 +6,13 @@ use rustc_session::cstore::ForeignModule;
 pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
     let mut modules = Vec::new();
     for id in tcx.hir().items() {
-        if !matches!(tcx.def_kind(id.def_id), DefKind::ForeignMod) {
+        if !matches!(tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
             continue;
         }
         let item = tcx.hir().item(id);
         if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
-            let foreign_items = items.iter().map(|it| it.id.def_id.to_def_id()).collect();
-            modules.push(ForeignModule { foreign_items, def_id: id.def_id.to_def_id() });
+            let foreign_items = items.iter().map(|it| it.id.owner_id.to_def_id()).collect();
+            modules.push(ForeignModule { foreign_items, def_id: id.owner_id.to_def_id() });
         }
     }
     modules
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 9abb5c74895..20a2e78299a 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -52,7 +52,7 @@ pub fn find_native_static_library(
         }
     }
 
-    sess.emit_fatal(MissingNativeLibrary { libname: name });
+    sess.emit_fatal(MissingNativeLibrary::new(name, verbatim.unwrap_or(false)));
 }
 
 fn find_bundled_library(
@@ -98,7 +98,7 @@ struct Collector<'tcx> {
 
 impl<'tcx> Collector<'tcx> {
     fn process_item(&mut self, id: rustc_hir::ItemId) {
-        if !matches!(self.tcx.def_kind(id.def_id), DefKind::ForeignMod) {
+        if !matches!(self.tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
             return;
         }
 
@@ -372,17 +372,17 @@ impl<'tcx> Collector<'tcx> {
                 }
                 _ => {
                     for child_item in foreign_mod_items {
-                        if self.tcx.def_kind(child_item.id.def_id).has_codegen_attrs()
+                        if self.tcx.def_kind(child_item.id.owner_id).has_codegen_attrs()
                             && self
                                 .tcx
-                                .codegen_fn_attrs(child_item.id.def_id)
+                                .codegen_fn_attrs(child_item.id.owner_id)
                                 .link_ordinal
                                 .is_some()
                         {
                             let link_ordinal_attr = self
                                 .tcx
                                 .hir()
-                                .attrs(child_item.id.def_id.into())
+                                .attrs(child_item.id.owner_id.into())
                                 .iter()
                                 .find(|a| a.has_name(sym::link_ordinal))
                                 .unwrap();
@@ -402,7 +402,7 @@ impl<'tcx> Collector<'tcx> {
                 filename,
                 kind,
                 cfg,
-                foreign_module: Some(it.def_id.to_def_id()),
+                foreign_module: Some(it.owner_id.to_def_id()),
                 wasm_import_module: wasm_import_module.map(|(name, _)| name),
                 verbatim,
                 dll_imports,
@@ -505,7 +505,7 @@ impl<'tcx> Collector<'tcx> {
     fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize {
         let argument_types: &List<Ty<'_>> = self.tcx.erase_late_bound_regions(
             self.tcx
-                .type_of(item.id.def_id)
+                .type_of(item.id.owner_id)
                 .fn_sig(self.tcx)
                 .inputs()
                 .map_bound(|slice| self.tcx.mk_type_list(slice.iter())),
@@ -557,7 +557,7 @@ impl<'tcx> Collector<'tcx> {
             }
         };
 
-        let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.def_id);
+        let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.owner_id);
         let import_name_type = codegen_fn_attrs
             .link_ordinal
             .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
@@ -567,7 +567,7 @@ impl<'tcx> Collector<'tcx> {
             import_name_type,
             calling_convention,
             span: item.span,
-            is_fn: self.tcx.def_kind(item.id.def_id).is_fn_like(),
+            is_fn: self.tcx.def_kind(item.id.owner_id).is_fn_like(),
         }
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 830417eea1a..8e80d794a13 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -15,7 +15,6 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
 use rustc_hir::diagnostic_items::DiagnosticItems;
-use rustc_hir::lang_items;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
@@ -773,7 +772,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
     }
 
     fn opt_item_name(self, item_index: DefIndex) -> Option<Symbol> {
-        self.def_key(item_index).disambiguated_data.data.get_opt_name()
+        let def_key = self.def_key(item_index);
+        def_key.disambiguated_data.data.get_opt_name().or_else(|| {
+            if def_key.disambiguated_data.data == DefPathData::Ctor {
+                let parent_index = def_key.parent.expect("no parent for a constructor");
+                self.def_key(parent_index).disambiguated_data.data.get_opt_name()
+            } else {
+                None
+            }
+        })
     }
 
     fn item_name(self, item_index: DefIndex) -> Symbol {
@@ -905,7 +912,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                 .get(self, item_id)
                 .unwrap_or_else(LazyArray::empty)
                 .decode(self)
-                .map(|index| self.get_variant(&self.def_kind(index), index, did))
+                .filter_map(|index| {
+                    let kind = self.def_kind(index);
+                    match kind {
+                        DefKind::Ctor(..) => None,
+                        _ => Some(self.get_variant(&kind, index, did)),
+                    }
+                })
                 .collect()
         } else {
             std::iter::once(self.get_variant(&kind, item_id, did)).collect()
@@ -953,7 +966,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
     }
 
     /// Iterates over the language items in the given crate.
-    fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
+    fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, LangItem)] {
         tcx.arena.alloc_from_iter(
             self.root
                 .lang_items
@@ -1029,50 +1042,27 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
 
                 callback(ModChild { ident, res, vis, span, macro_rules });
 
-                // For non-re-export structs and variants add their constructors to children.
-                // Re-export lists automatically contain constructors when necessary.
-                match kind {
-                    DefKind::Struct => {
-                        if let Some((ctor_def_id, ctor_kind)) =
-                            self.get_ctor_def_id_and_kind(child_index)
-                        {
-                            let ctor_res =
-                                Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
-                            let vis = self.get_visibility(ctor_def_id.index);
-                            callback(ModChild {
-                                ident,
-                                res: ctor_res,
-                                vis,
-                                span,
-                                macro_rules: false,
-                            });
-                        }
-                    }
-                    DefKind::Variant => {
-                        // Braced variants, unlike structs, generate unusable names in
-                        // value namespace, they are reserved for possible future use.
-                        // It's ok to use the variant's id as a ctor id since an
-                        // error will be reported on any use of such resolution anyway.
-                        let (ctor_def_id, ctor_kind) = self
-                            .get_ctor_def_id_and_kind(child_index)
-                            .unwrap_or((def_id, CtorKind::Fictive));
-                        let ctor_res =
-                            Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
-                        let mut vis = self.get_visibility(ctor_def_id.index);
-                        if ctor_def_id == def_id && vis.is_public() {
-                            // For non-exhaustive variants lower the constructor visibility to
-                            // within the crate. We only need this for fictive constructors,
-                            // for other constructors correct visibilities
-                            // were already encoded in metadata.
-                            let mut attrs = self.get_item_attrs(def_id.index, sess);
-                            if attrs.any(|item| item.has_name(sym::non_exhaustive)) {
-                                let crate_def_id = self.local_def_id(CRATE_DEF_INDEX);
-                                vis = ty::Visibility::Restricted(crate_def_id);
-                            }
+                // For non-reexport variants add their fictive constructors to children.
+                // Braced variants, unlike structs, generate unusable names in value namespace,
+                // they are reserved for possible future use. It's ok to use the variant's id as
+                // a ctor id since an error will be reported on any use of such resolution anyway.
+                // Reexport lists automatically contain such constructors when necessary.
+                if kind == DefKind::Variant && self.get_ctor_def_id_and_kind(child_index).is_none()
+                {
+                    let ctor_res =
+                        Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fictive), def_id);
+                    let mut vis = vis;
+                    if vis.is_public() {
+                        // For non-exhaustive variants lower the constructor visibility to
+                        // within the crate. We only need this for fictive constructors,
+                        // for other constructors correct visibilities
+                        // were already encoded in metadata.
+                        let mut attrs = self.get_item_attrs(def_id.index, sess);
+                        if attrs.any(|item| item.has_name(sym::non_exhaustive)) {
+                            vis = ty::Visibility::Restricted(self.local_def_id(CRATE_DEF_INDEX));
                         }
-                        callback(ModChild { ident, res: ctor_res, vis, span, macro_rules: false });
                     }
-                    _ => {}
+                    callback(ModChild { ident, res: ctor_res, vis, span, macro_rules: false });
                 }
             }
         }
@@ -1328,7 +1318,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         )
     }
 
-    fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
+    fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [LangItem] {
         tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode(self))
     }
 
@@ -1774,6 +1764,10 @@ impl CrateMetadata {
         self.root.has_global_allocator
     }
 
+    pub(crate) fn has_alloc_error_handler(&self) -> bool {
+        self.root.has_alloc_error_handler
+    }
+
     pub(crate) fn has_default_lib_allocator(&self) -> bool {
         self.root.has_default_lib_allocator
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index c4dff8b3f48..f475b0b3981 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -15,7 +15,6 @@ use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::{self, TyCtxt, Visibility};
 use rustc_session::cstore::{CrateSource, CrateStore};
-use rustc_session::utils::NativeLibKind;
 use rustc_session::{Session, StableCrateId};
 use rustc_span::hygiene::{ExpnHash, ExpnId};
 use rustc_span::source_map::{Span, Spanned};
@@ -224,6 +223,7 @@ provide! { tcx, def_id, other, cdata,
     fn_arg_names => { table }
     generator_kind => { table }
     trait_def => { table }
+    deduced_param_attrs => { table }
     collect_trait_impl_trait_tys => {
         Ok(cdata
             .root
@@ -255,6 +255,7 @@ provide! { tcx, def_id, other, cdata,
     is_panic_runtime => { cdata.root.panic_runtime }
     is_compiler_builtins => { cdata.root.compiler_builtins }
     has_global_allocator => { cdata.root.has_global_allocator }
+    has_alloc_error_handler => { cdata.root.has_alloc_error_handler }
     has_panic_handler => { cdata.root.has_panic_handler }
     is_profiler_runtime => { cdata.root.profiler_runtime }
     required_panic_strategy => { cdata.root.required_panic_strategy }
@@ -339,20 +340,11 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
     // resolve! Does this work? Unsure! That's what the issue is about
     *providers = Providers {
         allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(),
-        is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) {
-            Some(
-                NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified,
-            ) => true,
-            _ => false,
-        },
-        is_statically_included_foreign_item: |tcx, id| {
-            matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. }))
-        },
+        alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(),
         is_private_dep: |_tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
             false
         },
-        native_library_kind: |tcx, id| tcx.native_library(id).map(|l| l.kind),
         native_library: |tcx, id| {
             tcx.native_libraries(id.krate)
                 .iter()
@@ -474,6 +466,10 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
             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()
+        },
         postorder_cnums: |tcx, ()| {
             tcx.arena
                 .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
@@ -597,11 +593,6 @@ impl CStore {
         self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
     }
 
-    /// Decodes all traits in the crate (for rustdoc).
-    pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ {
-        self.get_crate_data(cnum).get_traits()
-    }
-
     /// Decodes all trait impls in the crate (for rustdoc).
     pub fn trait_impls_in_crate_untracked(
         &self,
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 68119598285..6a73e14e9f5 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -3,6 +3,7 @@ use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
 use crate::rmeta::table::TableBuilder;
 use crate::rmeta::*;
 
+use rustc_ast::Attribute;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::memmap::{Mmap, MmapMut};
@@ -16,7 +17,7 @@ use rustc_hir::def_id::{
 };
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::lang_items;
+use rustc_hir::lang_items::LangItem;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::{
@@ -30,7 +31,7 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
 use rustc_middle::util::common::to_readable_str;
 use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
-use rustc_session::config::CrateType;
+use rustc_session::config::{CrateType, OptLevel};
 use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
 use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind};
 use rustc_span::symbol::{sym, Symbol};
@@ -669,6 +670,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
                 edition: tcx.sess.edition(),
                 has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
+                has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE),
                 has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
                 has_default_lib_allocator: tcx
                     .sess
@@ -764,6 +766,38 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 }
 
+/// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and
+/// useful in downstream crates. Local-only attributes are an obvious example, but some
+/// rustdoc-specific attributes can equally be of use while documenting the current crate only.
+///
+/// Removing these superfluous attributes speeds up compilation by making the metadata smaller.
+///
+/// Note: the `is_def_id_public` parameter is used to cache whether the given `DefId` has a public
+/// visibility: this is a piece of data that can be computed once per defid, and not once per
+/// attribute. Some attributes would only be usable downstream if they are public.
+#[inline]
+fn should_encode_attr(
+    tcx: TyCtxt<'_>,
+    attr: &Attribute,
+    def_id: LocalDefId,
+    is_def_id_public: &mut Option<bool>,
+) -> bool {
+    if rustc_feature::is_builtin_only_local(attr.name_or_empty()) {
+        // Attributes marked local-only don't need to be encoded for downstream crates.
+        false
+    } else if attr.doc_str().is_some() {
+        // We keep all public doc comments because they might be "imported" into downstream crates
+        // if they use `#[doc(inline)]` to copy an item's documentation into their own.
+        *is_def_id_public.get_or_insert_with(|| tcx.effective_visibilities(()).is_exported(def_id))
+    } else if attr.has_name(sym::doc) {
+        // If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can
+        // remove it. It won't be inlinable in downstream crates.
+        attr.meta_item_list().map(|l| l.iter().any(|l| !l.has_name(sym::inline))).unwrap_or(false)
+    } else {
+        true
+    }
+}
+
 fn should_encode_visibility(def_kind: DefKind) -> bool {
     match def_kind {
         DefKind::Mod
@@ -1059,43 +1093,6 @@ fn should_encode_const(def_kind: DefKind) -> bool {
     }
 }
 
-fn should_encode_constness(def_kind: DefKind) -> bool {
-    match def_kind {
-        DefKind::Struct
-        | DefKind::Union
-        | DefKind::Enum
-        | DefKind::Trait
-        | DefKind::AssocTy
-        | DefKind::Fn
-        | DefKind::Const
-        | DefKind::Static(..)
-        | DefKind::Ctor(..)
-        | DefKind::AssocFn
-        | DefKind::AssocConst
-        | DefKind::AnonConst
-        | DefKind::InlineConst
-        | DefKind::OpaqueTy
-        | DefKind::ImplTraitPlaceholder
-        | DefKind::Impl
-        | DefKind::Closure
-        | DefKind::Generator
-        | DefKind::TyAlias => true,
-        DefKind::Variant
-        | DefKind::TraitAlias
-        | DefKind::ForeignTy
-        | DefKind::Field
-        | DefKind::TyParam
-        | DefKind::Mod
-        | DefKind::ForeignMod
-        | DefKind::ConstParam
-        | DefKind::Macro(..)
-        | DefKind::Use
-        | DefKind::LifetimeParam
-        | DefKind::GlobalAsm
-        | DefKind::ExternCrate => false,
-    }
-}
-
 fn should_encode_trait_impl_trait_tys<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
     if tcx.def_kind(def_id) != DefKind::AssocFn {
         return false;
@@ -1126,12 +1123,14 @@ fn should_encode_trait_impl_trait_tys<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) ->
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     fn encode_attrs(&mut self, def_id: LocalDefId) {
-        let mut attrs = self
-            .tcx
+        let tcx = self.tcx;
+        let mut is_public: Option<bool> = None;
+
+        let mut attrs = tcx
             .hir()
-            .attrs(self.tcx.hir().local_def_id_to_hir_id(def_id))
+            .attrs(tcx.hir().local_def_id_to_hir_id(def_id))
             .iter()
-            .filter(|attr| !rustc_feature::is_builtin_only_local(attr.name_or_empty()));
+            .filter(move |attr| should_encode_attr(tcx, attr, def_id, &mut is_public));
 
         record_array!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone());
         if attrs.any(|attr| attr.may_have_doc_links()) {
@@ -1202,9 +1201,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             {
                 record!(self.tables.trait_impl_trait_tys[def_id] <- table);
             }
-            if should_encode_constness(def_kind) {
-                self.tables.constness.set(def_id.index, tcx.constness(def_id));
-            }
         }
         let inherent_impls = tcx.crate_inherent_impls(());
         for (def_id, implementations) in inherent_impls.inherent_impls.iter() {
@@ -1232,6 +1228,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         };
 
         record!(self.tables.variant_data[def_id] <- data);
+        self.tables.constness.set(def_id.index, hir::Constness::Const);
         record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
             assert!(f.did.is_local());
             f.did.index
@@ -1259,6 +1256,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         };
 
         record!(self.tables.variant_data[def_id] <- data);
+        self.tables.constness.set(def_id.index, hir::Constness::Const);
         if variant.ctor_kind == CtorKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
         }
@@ -1292,14 +1290,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                         // from name resolution point of view.
                         hir::ItemKind::ForeignMod { items, .. } => {
                             for foreign_item in items {
-                                yield foreign_item.id.def_id.def_id.local_def_index;
+                                yield foreign_item.id.owner_id.def_id.local_def_index;
                             }
                         }
                         // Only encode named non-reexport children, reexports are encoded
                         // separately and unnamed items are not used by name resolution.
                         hir::ItemKind::ExternCrate(..) => continue,
-                        _ if tcx.def_key(item_id.def_id.to_def_id()).get_opt_name().is_some() => {
-                            yield item_id.def_id.def_id.local_def_index;
+                        hir::ItemKind::Struct(ref vdata, _) => {
+                            yield item_id.owner_id.def_id.local_def_index;
+                            // Encode constructors which take a separate slot in value namespace.
+                            if let Some(ctor_hir_id) = vdata.ctor_hir_id() {
+                                yield tcx.hir().local_def_id(ctor_hir_id).local_def_index;
+                            }
+                        }
+                        _ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => {
+                            yield item_id.owner_id.def_id.local_def_index;
                         }
                         _ => continue,
                     }
@@ -1322,6 +1327,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         record!(self.tables.repr_options[def_id] <- adt_def.repr());
         record!(self.tables.variant_data[def_id] <- data);
+        self.tables.constness.set(def_id.index, hir::Constness::Const);
         if variant.ctor_kind == CtorKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
         }
@@ -1357,6 +1363,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     }
                 };
                 self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
+                self.tables.constness.set(def_id.index, hir::Constness::NotConst);
             }
             ty::AssocKind::Type => {
                 self.encode_explicit_item_bounds(def_id);
@@ -1381,6 +1388,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
                 self.tables.asyncness.set(def_id.index, sig.header.asyncness);
                 record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
+                // Can be inside `impl const Trait`, so using sig.header.constness is not reliable
+                let constness = if self.tcx.is_const_fn_raw(def_id) {
+                    hir::Constness::Const
+                } else {
+                    hir::Constness::NotConst
+                };
+                self.tables.constness.set(def_id.index, constness);
             }
             ty::AssocKind::Const | ty::AssocKind::Type => {}
         }
@@ -1441,6 +1455,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
             }
         }
+
+        // Encode all the deduced parameter attributes for everything that has MIR, even for items
+        // that can't be inlined. But don't if we aren't optimizing in non-incremental mode, to
+        // save the query traffic.
+        if tcx.sess.opts.output_types.should_codegen()
+            && tcx.sess.opts.optimize != OptLevel::No
+            && tcx.sess.opts.incremental.is_none()
+        {
+            for &local_def_id in tcx.mir_keys(()) {
+                if let DefKind::AssocFn | DefKind::Fn = tcx.def_kind(local_def_id) {
+                    record_array!(self.tables.deduced_param_attrs[local_def_id.to_def_id()] <-
+                        self.tcx.deduced_param_attrs(local_def_id.to_def_id()));
+                }
+            }
+        }
     }
 
     fn encode_stability(&mut self, def_id: DefId) {
@@ -1503,6 +1532,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             hir::ItemKind::Fn(ref sig, .., body) => {
                 self.tables.asyncness.set(def_id.index, sig.header.asyncness);
                 record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
+                self.tables.constness.set(def_id.index, sig.header.constness);
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
                 if macro_def.macro_rules {
@@ -1511,7 +1541,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record!(self.tables.macro_definition[def_id] <- &*macro_def.body);
             }
             hir::ItemKind::Mod(ref m) => {
-                return self.encode_info_for_mod(item.def_id.def_id, m);
+                return self.encode_info_for_mod(item.owner_id.def_id, m);
             }
             hir::ItemKind::OpaqueTy(..) => {
                 self.encode_explicit_item_bounds(def_id);
@@ -1523,6 +1553,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             hir::ItemKind::Struct(ref struct_def, _) => {
                 let adt_def = self.tcx.adt_def(def_id);
                 record!(self.tables.repr_options[def_id] <- adt_def.repr());
+                self.tables.constness.set(def_id.index, hir::Constness::Const);
 
                 // Encode def_ids for each field and method
                 // for methods, write all the stuff get_trait_method
@@ -1551,8 +1582,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     is_non_exhaustive: variant.is_field_list_non_exhaustive(),
                 });
             }
-            hir::ItemKind::Impl(hir::Impl { defaultness, .. }) => {
+            hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
                 self.tables.impl_defaultness.set(def_id.index, *defaultness);
+                self.tables.constness.set(def_id.index, *constness);
 
                 let trait_ref = self.tcx.impl_trait_ref(def_id);
                 if let Some(trait_ref) = trait_ref {
@@ -1594,12 +1626,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         };
         // FIXME(eddyb) there should be a nicer way to do this.
         match item.kind {
-            hir::ItemKind::Enum(..) => record_array!(self.tables.children[def_id] <-
-                self.tcx.adt_def(def_id).variants().iter().map(|v| {
-                    assert!(v.def_id.is_local());
-                    v.def_id.index
-                })
-            ),
+            hir::ItemKind::Enum(..) => {
+                record_array!(self.tables.children[def_id] <- iter::from_generator(||
+                    for variant in tcx.adt_def(def_id).variants() {
+                        yield variant.def_id.index;
+                        // Encode constructors which take a separate slot in value namespace.
+                        if let Some(ctor_def_id) = variant.ctor_def_id {
+                            yield ctor_def_id.index;
+                        }
+                    }
+                ))
+            }
             hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
                 record_array!(self.tables.children[def_id] <-
                     self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| {
@@ -1636,7 +1673,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         // normally in the visitor walk.
         match item.kind {
             hir::ItemKind::Enum(..) => {
-                let def = self.tcx.adt_def(item.def_id.to_def_id());
+                let def = self.tcx.adt_def(item.owner_id.to_def_id());
                 for (i, variant) in def.variants().iter_enumerated() {
                     self.encode_enum_variant_info(def, i);
 
@@ -1646,7 +1683,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 }
             }
             hir::ItemKind::Struct(ref struct_def, _) => {
-                let def = self.tcx.adt_def(item.def_id.to_def_id());
+                let def = self.tcx.adt_def(item.owner_id.to_def_id());
                 // If the struct has a constructor, encode it.
                 if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
                     let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
@@ -1655,13 +1692,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             hir::ItemKind::Impl { .. } => {
                 for &trait_item_def_id in
-                    self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
+                    self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter()
                 {
                     self.encode_info_for_impl_item(trait_item_def_id);
                 }
             }
             hir::ItemKind::Trait(..) => {
-                for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
+                for &item_def_id in
+                    self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter()
                 {
                     self.encode_info_for_trait_item(item_def_id);
                 }
@@ -1867,22 +1905,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.lazy_array(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index)))
     }
 
-    fn encode_lang_items(&mut self) -> LazyArray<(DefIndex, usize)> {
+    fn encode_lang_items(&mut self) -> LazyArray<(DefIndex, LangItem)> {
         empty_proc_macro!(self);
-        let tcx = self.tcx;
-        let lang_items = tcx.lang_items();
-        let lang_items = lang_items.items().iter();
-        self.lazy_array(lang_items.enumerate().filter_map(|(i, &opt_def_id)| {
-            if let Some(def_id) = opt_def_id {
-                if def_id.is_local() {
-                    return Some((def_id.index, i));
-                }
-            }
-            None
+        let lang_items = self.tcx.lang_items().iter();
+        self.lazy_array(lang_items.filter_map(|(lang_item, def_id)| {
+            def_id.as_local().map(|id| (id.local_def_index, lang_item))
         }))
     }
 
-    fn encode_lang_items_missing(&mut self) -> LazyArray<lang_items::LangItem> {
+    fn encode_lang_items_missing(&mut self) -> LazyArray<LangItem> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
         self.lazy_array(&tcx.lang_items().missing)
@@ -1902,8 +1933,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             FxHashMap::default();
 
         for id in tcx.hir().items() {
-            if matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
-                if let Some(trait_ref) = tcx.impl_trait_ref(id.def_id) {
+            if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
+                if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) {
                     let simplified_self_ty = fast_reject::simplify_type(
                         self.tcx,
                         trait_ref.self_ty(),
@@ -1913,7 +1944,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     fx_hash_map
                         .entry(trait_ref.def_id)
                         .or_default()
-                        .push((id.def_id.def_id.local_def_index, simplified_self_ty));
+                        .push((id.owner_id.def_id.local_def_index, simplified_self_ty));
                 }
             }
         }
@@ -2054,12 +2085,12 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> {
         intravisit::walk_item(self, item);
         match item.kind {
             hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these
-            _ => self.encode_info_for_item(item.def_id.to_def_id(), item),
+            _ => self.encode_info_for_item(item.owner_id.to_def_id(), item),
         }
     }
     fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) {
         intravisit::walk_foreign_item(self, ni);
-        self.encode_info_for_foreign_item(ni.def_id.to_def_id(), ni);
+        self.encode_info_for_foreign_item(ni.owner_id.to_def_id(), ni);
     }
     fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
         intravisit::walk_generics(self, generics);
@@ -2278,8 +2309,8 @@ pub fn provide(providers: &mut Providers) {
 
             let mut traits = Vec::new();
             for id in tcx.hir().items() {
-                if matches!(tcx.def_kind(id.def_id), DefKind::Trait | DefKind::TraitAlias) {
-                    traits.push(id.def_id.to_def_id())
+                if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) {
+                    traits.push(id.owner_id.to_def_id())
                 }
             }
 
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a509ecdf759..aa6d378a43a 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -12,7 +12,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId};
 use rustc_hir::definitions::DefKey;
-use rustc_hir::lang_items;
+use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::{BitSet, FiniteBitSet};
 use rustc_index::vec::IndexVec;
 use rustc_middle::metadata::ModChild;
@@ -23,7 +23,7 @@ use rustc_middle::mir;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, ReprOptions, Ty};
-use rustc_middle::ty::{GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt};
+use rustc_middle::ty::{DeducedParamAttrs, GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt};
 use rustc_serialize::opaque::FileEncoder;
 use rustc_session::config::SymbolManglingVersion;
 use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
@@ -223,6 +223,7 @@ pub(crate) struct CrateRoot {
     panic_in_drop_strategy: PanicStrategy,
     edition: Edition,
     has_global_allocator: bool,
+    has_alloc_error_handler: bool,
     has_panic_handler: bool,
     has_default_lib_allocator: bool,
 
@@ -230,8 +231,8 @@ pub(crate) struct CrateRoot {
     dylib_dependency_formats: LazyArray<Option<LinkagePreference>>,
     lib_features: LazyArray<(Symbol, Option<Symbol>)>,
     stability_implications: LazyArray<(Symbol, Symbol)>,
-    lang_items: LazyArray<(DefIndex, usize)>,
-    lang_items_missing: LazyArray<lang_items::LangItem>,
+    lang_items: LazyArray<(DefIndex, LangItem)>,
+    lang_items_missing: LazyArray<LangItem>,
     diagnostic_items: LazyArray<(Symbol, DefIndex)>,
     native_libraries: LazyArray<NativeLib>,
     foreign_modules: LazyArray<ForeignModule>,
@@ -402,6 +403,7 @@ define_tables! {
     macro_definition: Table<DefIndex, LazyValue<ast::MacArgs>>,
     proc_macro: Table<DefIndex, MacroKind>,
     module_reexports: Table<DefIndex, LazyArray<ModChild>>,
+    deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>,
 
     trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>,
 }
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index de916ea8c49..8e7d0cf2ab1 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -32,7 +32,7 @@ rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 rustc_type_ir = { path = "../rustc_type_ir" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
 tracing = "0.1"
 
 [features]
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index d2847e4bc12..f8aae86fe3d 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -77,7 +77,7 @@ macro_rules! arena_types {
                     rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>>
                 >,
             [] all_traits: Vec<rustc_hir::def_id::DefId>,
-            [] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels,
+            [] effective_visibilities: rustc_middle::middle::privacy::EffectiveVisibilities,
             [] foreign_module: rustc_session::cstore::ForeignModule,
             [] foreign_modules: Vec<rustc_session::cstore::ForeignModule>,
             [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
@@ -96,7 +96,7 @@ macro_rules! arena_types {
             // since we need to allocate this type on both the `rustc_hir` arena
             // (during lowering) and the `librustc_middle` arena (for decoding MIR)
             [decode] asm_template: rustc_ast::InlineAsmTemplatePiece,
-            [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>,
+            [decode] used_trait_imports: rustc_data_structures::unord::UnordSet<rustc_hir::def_id::LocalDefId>,
             [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>,
             [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
 
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index e69cb546d15..43903e6739f 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -4,7 +4,7 @@ use rustc_span::Span;
 use crate::ty::Ty;
 
 #[derive(Diagnostic)]
-#[diag(middle::drop_check_overflow, code = "E0320")]
+#[diag(middle_drop_check_overflow, code = "E0320")]
 #[note]
 pub struct DropCheckOverflow<'tcx> {
     #[primary_span]
@@ -14,7 +14,7 @@ pub struct DropCheckOverflow<'tcx> {
 }
 
 #[derive(Diagnostic)]
-#[diag(middle::opaque_hidden_type_mismatch)]
+#[diag(middle_opaque_hidden_type_mismatch)]
 pub struct OpaqueHiddenTypeMismatch<'tcx> {
     pub self_ty: Ty<'tcx>,
     pub other_ty: Ty<'tcx>,
@@ -27,12 +27,12 @@ pub struct OpaqueHiddenTypeMismatch<'tcx> {
 
 #[derive(Subdiagnostic)]
 pub enum TypeMismatchReason {
-    #[label(middle::conflict_types)]
+    #[label(middle_conflict_types)]
     ConflictType {
         #[primary_span]
         span: Span,
     },
-    #[note(middle::previous_use_here)]
+    #[note(middle_previous_use_here)]
     PreviousUse {
         #[primary_span]
         span: Span,
@@ -40,7 +40,7 @@ pub enum TypeMismatchReason {
 }
 
 #[derive(Diagnostic)]
-#[diag(middle::limit_invalid)]
+#[diag(middle_limit_invalid)]
 pub struct LimitInvalid<'a> {
     #[primary_span]
     pub span: Span,
@@ -50,8 +50,17 @@ pub struct LimitInvalid<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(middle::const_eval_non_int)]
+#[diag(middle_const_eval_non_int)]
 pub struct ConstEvalNonIntError {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(middle_strict_coherence_needs_negative_coherence)]
+pub(crate) struct StrictCoherenceNeedsNegativeCoherence {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub attr_span: Option<Span>,
+}
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 302f12a6f7d..83a4d16d7a9 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -354,19 +354,19 @@ impl<'hir> Map<'hir> {
     }
 
     pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
-        self.tcx.hir_owner(id.def_id).unwrap().node.expect_item()
+        self.tcx.hir_owner(id.owner_id).unwrap().node.expect_item()
     }
 
     pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> {
-        self.tcx.hir_owner(id.def_id).unwrap().node.expect_trait_item()
+        self.tcx.hir_owner(id.owner_id).unwrap().node.expect_trait_item()
     }
 
     pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> {
-        self.tcx.hir_owner(id.def_id).unwrap().node.expect_impl_item()
+        self.tcx.hir_owner(id.owner_id).unwrap().node.expect_impl_item()
     }
 
     pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
-        self.tcx.hir_owner(id.def_id).unwrap().node.expect_foreign_item()
+        self.tcx.hir_owner(id.owner_id).unwrap().node.expect_foreign_item()
     }
 
     pub fn body(self, id: BodyId) -> &'hir Body<'hir> {
@@ -1377,14 +1377,14 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
 
     fn visit_item(&mut self, item: &'hir Item<'hir>) {
         if associated_body(Node::Item(item)).is_some() {
-            self.body_owners.push(item.def_id.def_id);
+            self.body_owners.push(item.owner_id.def_id);
         }
 
         self.items.push(item.item_id());
 
         // Items that are modules are handled here instead of in visit_mod.
         if let ItemKind::Mod(module) = &item.kind {
-            self.submodules.push(item.def_id);
+            self.submodules.push(item.owner_id);
             // A module collector does not recurse inside nested modules.
             if self.crate_collector {
                 intravisit::walk_mod(self, module, item.hir_id());
@@ -1413,7 +1413,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
 
     fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) {
         if associated_body(Node::TraitItem(item)).is_some() {
-            self.body_owners.push(item.def_id.def_id);
+            self.body_owners.push(item.owner_id.def_id);
         }
 
         self.trait_items.push(item.trait_item_id());
@@ -1422,7 +1422,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
 
     fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
         if associated_body(Node::ImplItem(item)).is_some() {
-            self.body_owners.push(item.def_id.def_id);
+            self.body_owners.push(item.owner_id.def_id);
         }
 
         self.impl_items.push(item.impl_item_id());
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 1ce98a03c8a..1c6264ad036 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -67,10 +67,10 @@ impl ModuleItems {
     pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
         self.items
             .iter()
-            .map(|id| id.def_id.def_id)
-            .chain(self.trait_items.iter().map(|id| id.def_id.def_id))
-            .chain(self.impl_items.iter().map(|id| id.def_id.def_id))
-            .chain(self.foreign_items.iter().map(|id| id.def_id.def_id))
+            .map(|id| id.owner_id.def_id)
+            .chain(self.trait_items.iter().map(|id| id.owner_id.def_id))
+            .chain(self.impl_items.iter().map(|id| id.owner_id.def_id))
+            .chain(self.foreign_items.iter().map(|id| id.owner_id.def_id))
     }
 
     pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) {
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 45c84680ad2..a58cbc3767e 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -55,6 +55,7 @@
 #![feature(drain_filter)]
 #![feature(intra_doc_pointers)]
 #![feature(yeet_expr)]
+#![feature(result_option_inspect)]
 #![feature(const_option)]
 #![recursion_limit = "512"]
 #![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index d95c5cbd654..79522bd0b2b 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -274,6 +274,39 @@ pub fn explain_lint_level_source(
     }
 }
 
+/// The innermost function for emitting lints.
+///
+/// If you are loocking to implement a lint, look for higher level functions,
+/// for example:
+/// - [`TyCtxt::emit_spanned_lint`]
+/// - [`TyCtxt::struct_span_lint_hir`]
+/// - [`TyCtxt::emit_lint`]
+/// - [`TyCtxt::struct_lint_node`]
+/// - `LintContext::lookup`
+///
+/// ## `decorate` signature
+///
+/// The return value of `decorate` is ignored by this function. So what is the
+/// point of returning `&'b mut DiagnosticBuilder<'a, ()>`?
+///
+/// There are 2 reasons for this signature.
+///
+/// First of all, it prevents accidental use of `.emit()` -- it's clear that the
+/// builder will be later used and shouldn't be emitted right away (this is
+/// especially important because the old API expected you to call `.emit()` in
+/// the closure).
+///
+/// Second of all, it makes the most common case of adding just a single label
+/// /suggestion much nicer, since [`DiagnosticBuilder`] methods return
+/// `&mut DiagnosticBuilder`, you can just chain methods, without needed
+/// awkward `{ ...; }`:
+/// ```ignore pseudo-code
+/// struct_lint_level(
+///     ...,
+///     |lint| lint.span_label(sp, "lbl")
+///     //          ^^^^^^^^^^^^^^^^^^^^^ returns `&mut DiagnosticBuilder` by default
+/// )
+/// ```
 pub fn struct_lint_level(
     sess: &Session,
     lint: &'static Lint,
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 0e85c60a363..01fe72de612 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -54,13 +54,22 @@ macro_rules! TrivialTypeTraversalImpls {
             impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty {
                 fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
                     self,
-                    _: &mut F
-                ) -> ::std::result::Result<$ty, F::Error> {
+                    _: &mut F,
+                ) -> ::std::result::Result<Self, F::Error> {
                     Ok(self)
                 }
+
+                #[inline]
+                fn fold_with<F: $crate::ty::fold::TypeFolder<$tcx>>(
+                    self,
+                    _: &mut F,
+                ) -> Self {
+                    self
+                }
             }
 
             impl<$tcx> $crate::ty::visit::TypeVisitable<$tcx> for $ty {
+                #[inline]
                 fn visit_with<F: $crate::ty::visit::TypeVisitor<$tcx>>(
                     &self,
                     _: &mut F)
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
index 31c20fa14aa..dd4332d0db6 100644
--- a/compiler/rustc_middle/src/middle/lang_items.rs
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -36,10 +36,6 @@ impl<'tcx> TyCtxt<'tcx> {
             _ => None,
         }
     }
-
-    pub fn is_weak_lang_item(self, item_def_id: DefId) -> bool {
-        self.lang_items().is_weak_lang_item(item_def_id)
-    }
 }
 
 /// Returns `true` if the specified `lang_item` must be present for this
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index c595fbec0dd..ffbd6d10da6 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -1,100 +1,108 @@
 //! A pass that checks to make sure private fields and methods aren't used
 //! outside their scopes. This pass will also generate a set of exported items
 //! which are available for use externally when compiled as a library.
-use crate::ty::Visibility;
+use crate::ty::{DefIdTree, Visibility};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_span::def_id::LocalDefId;
-use std::hash::Hash;
 
-/// Represents the levels of accessibility an item can have.
+/// Represents the levels of effective visibility an item can have.
 ///
-/// The variants are sorted in ascending order of accessibility.
+/// The variants are sorted in ascending order of directness.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)]
-pub enum AccessLevel {
-    /// Superset of `AccessLevel::Reachable` used to mark impl Trait items.
-    ReachableFromImplTrait,
-    /// Exported items + items participating in various kinds of public interfaces,
-    /// but not directly nameable. For example, if function `fn f() -> T {...}` is
-    /// public, then type `T` is reachable. Its values can be obtained by other crates
-    /// even if the type itself is not nameable.
+pub enum Level {
+    /// Superset of `Reachable` including items leaked through return position `impl Trait`.
+    ReachableThroughImplTrait,
+    /// Item is either reexported, or leaked through any kind of interface.
+    /// For example, if function `fn f() -> T {...}` is directly public, then type `T` is publicly
+    /// reachable and its values can be obtained by other crates even if the type itself is not
+    /// nameable.
     Reachable,
-    /// Public items + items accessible to other crates with the help of `pub use` re-exports.
-    Exported,
-    /// Items accessible to other crates directly, without the help of re-exports.
-    Public,
+    /// Item is accessible either directly, or with help of `use` reexports.
+    Reexported,
+    /// Item is directly accessible, without help of reexports.
+    Direct,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Default)]
+impl Level {
+    pub fn all_levels() -> [Level; 4] {
+        [Level::Direct, Level::Reexported, Level::Reachable, Level::ReachableThroughImplTrait]
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
 pub struct EffectiveVisibility {
-    public: Option<Visibility>,
-    exported: Option<Visibility>,
-    reachable: Option<Visibility>,
-    reachable_from_impl_trait: Option<Visibility>,
+    direct: Visibility,
+    reexported: Visibility,
+    reachable: Visibility,
+    reachable_through_impl_trait: Visibility,
 }
 
 impl EffectiveVisibility {
-    pub fn get(&self, tag: AccessLevel) -> Option<&Visibility> {
-        match tag {
-            AccessLevel::Public => &self.public,
-            AccessLevel::Exported => &self.exported,
-            AccessLevel::Reachable => &self.reachable,
-            AccessLevel::ReachableFromImplTrait => &self.reachable_from_impl_trait,
+    pub fn at_level(&self, level: Level) -> &Visibility {
+        match level {
+            Level::Direct => &self.direct,
+            Level::Reexported => &self.reexported,
+            Level::Reachable => &self.reachable,
+            Level::ReachableThroughImplTrait => &self.reachable_through_impl_trait,
         }
-        .as_ref()
     }
 
-    fn get_mut(&mut self, tag: AccessLevel) -> &mut Option<Visibility> {
-        match tag {
-            AccessLevel::Public => &mut self.public,
-            AccessLevel::Exported => &mut self.exported,
-            AccessLevel::Reachable => &mut self.reachable,
-            AccessLevel::ReachableFromImplTrait => &mut self.reachable_from_impl_trait,
+    fn at_level_mut(&mut self, level: Level) -> &mut Visibility {
+        match level {
+            Level::Direct => &mut self.direct,
+            Level::Reexported => &mut self.reexported,
+            Level::Reachable => &mut self.reachable,
+            Level::ReachableThroughImplTrait => &mut self.reachable_through_impl_trait,
         }
     }
 
-    pub fn is_public_at_level(&self, tag: AccessLevel) -> bool {
-        self.get(tag).map_or(false, |vis| vis.is_public())
+    pub fn is_public_at_level(&self, level: Level) -> bool {
+        self.at_level(level).is_public()
+    }
+
+    pub fn from_vis(vis: Visibility) -> EffectiveVisibility {
+        EffectiveVisibility {
+            direct: vis,
+            reexported: vis,
+            reachable: vis,
+            reachable_through_impl_trait: vis,
+        }
     }
 }
 
-/// Holds a map of accessibility levels for reachable HIR nodes.
-#[derive(Debug, Clone)]
-pub struct AccessLevels<Id = LocalDefId> {
-    map: FxHashMap<Id, EffectiveVisibility>,
+/// Holds a map of effective visibilities for reachable HIR nodes.
+#[derive(Default, Clone, Debug)]
+pub struct EffectiveVisibilities {
+    map: FxHashMap<LocalDefId, EffectiveVisibility>,
 }
 
-impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
-    pub fn is_public_at_level(&self, id: Id, tag: AccessLevel) -> bool {
-        self.get_effective_vis(id)
-            .map_or(false, |effective_vis| effective_vis.is_public_at_level(tag))
+impl EffectiveVisibilities {
+    pub fn is_public_at_level(&self, id: LocalDefId, level: Level) -> bool {
+        self.effective_vis(id)
+            .map_or(false, |effective_vis| effective_vis.is_public_at_level(level))
     }
 
-    /// See `AccessLevel::Reachable`.
-    pub fn is_reachable(&self, id: Id) -> bool {
-        self.is_public_at_level(id, AccessLevel::Reachable)
+    /// See `Level::Reachable`.
+    pub fn is_reachable(&self, id: LocalDefId) -> bool {
+        self.is_public_at_level(id, Level::Reachable)
     }
 
-    /// See `AccessLevel::Exported`.
-    pub fn is_exported(&self, id: Id) -> bool {
-        self.is_public_at_level(id, AccessLevel::Exported)
+    /// See `Level::Reexported`.
+    pub fn is_exported(&self, id: LocalDefId) -> bool {
+        self.is_public_at_level(id, Level::Reexported)
     }
 
-    /// See `AccessLevel::Public`.
-    pub fn is_public(&self, id: Id) -> bool {
-        self.is_public_at_level(id, AccessLevel::Public)
+    /// See `Level::Direct`.
+    pub fn is_directly_public(&self, id: LocalDefId) -> bool {
+        self.is_public_at_level(id, Level::Direct)
     }
 
-    pub fn get_access_level(&self, id: Id) -> Option<AccessLevel> {
-        self.get_effective_vis(id).and_then(|effective_vis| {
-            for level in [
-                AccessLevel::Public,
-                AccessLevel::Exported,
-                AccessLevel::Reachable,
-                AccessLevel::ReachableFromImplTrait,
-            ] {
+    pub fn public_at_level(&self, id: LocalDefId) -> Option<Level> {
+        self.effective_vis(id).and_then(|effective_vis| {
+            for level in Level::all_levels() {
                 if effective_vis.is_public_at_level(level) {
                     return Some(level);
                 }
@@ -103,43 +111,92 @@ impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
         })
     }
 
-    pub fn set_access_level(&mut self, id: Id, tag: AccessLevel) {
-        let mut effective_vis = self.get_effective_vis(id).copied().unwrap_or_default();
-        for level in [
-            AccessLevel::Public,
-            AccessLevel::Exported,
-            AccessLevel::Reachable,
-            AccessLevel::ReachableFromImplTrait,
-        ] {
-            if level <= tag {
-                *effective_vis.get_mut(level) = Some(Visibility::Public);
-            }
-        }
-        self.map.insert(id, effective_vis);
-    }
-
-    pub fn get_effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
+    pub fn effective_vis(&self, id: LocalDefId) -> Option<&EffectiveVisibility> {
         self.map.get(&id)
     }
 
-    pub fn iter(&self) -> impl Iterator<Item = (&Id, &EffectiveVisibility)> {
+    pub fn iter(&self) -> impl Iterator<Item = (&LocalDefId, &EffectiveVisibility)> {
         self.map.iter()
     }
 
-    pub fn map_id<OutId: Hash + Eq + Copy>(&self, f: impl Fn(Id) -> OutId) -> AccessLevels<OutId> {
-        AccessLevels { map: self.map.iter().map(|(k, v)| (f(*k), *v)).collect() }
+    pub fn set_public_at_level(
+        &mut self,
+        id: LocalDefId,
+        default_vis: impl FnOnce() -> Visibility,
+        level: Level,
+    ) {
+        let mut effective_vis = self
+            .effective_vis(id)
+            .copied()
+            .unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis()));
+        for l in Level::all_levels() {
+            if l <= level {
+                *effective_vis.at_level_mut(l) = Visibility::Public;
+            }
+        }
+        self.map.insert(id, effective_vis);
     }
-}
 
-impl<Id> Default for AccessLevels<Id> {
-    fn default() -> Self {
-        AccessLevels { map: Default::default() }
+    // `parent_id` is not necessarily a parent in source code tree,
+    // it is the node from which the maximum effective visibility is inherited.
+    pub fn update(
+        &mut self,
+        id: LocalDefId,
+        nominal_vis: Visibility,
+        default_vis: impl FnOnce() -> Visibility,
+        parent_id: LocalDefId,
+        level: Level,
+        tree: impl DefIdTree,
+    ) -> bool {
+        let mut changed = false;
+        let mut current_effective_vis = self.effective_vis(id).copied().unwrap_or_else(|| {
+            if id.is_top_level_module() {
+                EffectiveVisibility::from_vis(Visibility::Public)
+            } else {
+                EffectiveVisibility::from_vis(default_vis())
+            }
+        });
+        if let Some(inherited_effective_vis) = self.effective_vis(parent_id) {
+            let mut inherited_effective_vis_at_prev_level =
+                *inherited_effective_vis.at_level(level);
+            let mut calculated_effective_vis = inherited_effective_vis_at_prev_level;
+            for l in Level::all_levels() {
+                if level >= l {
+                    let inherited_effective_vis_at_level = *inherited_effective_vis.at_level(l);
+                    let current_effective_vis_at_level = current_effective_vis.at_level_mut(l);
+                    // effective visibility for id shouldn't be recalculated if
+                    // inherited from parent_id effective visibility isn't changed at next level
+                    if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level
+                        && level != l)
+                    {
+                        calculated_effective_vis =
+                            if nominal_vis.is_at_least(inherited_effective_vis_at_level, tree) {
+                                inherited_effective_vis_at_level
+                            } else {
+                                nominal_vis
+                            };
+                    }
+                    // effective visibility can't be decreased at next update call for the
+                    // same id
+                    if *current_effective_vis_at_level != calculated_effective_vis
+                        && calculated_effective_vis
+                            .is_at_least(*current_effective_vis_at_level, tree)
+                    {
+                        changed = true;
+                        *current_effective_vis_at_level = calculated_effective_vis;
+                    }
+                    inherited_effective_vis_at_prev_level = inherited_effective_vis_at_level;
+                }
+            }
+        }
+        self.map.insert(id, current_effective_vis);
+        changed
     }
 }
 
-impl<'a> HashStable<StableHashingContext<'a>> for AccessLevels {
+impl<'a> HashStable<StableHashingContext<'a>> for EffectiveVisibilities {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let AccessLevels { ref map } = *self;
+        let EffectiveVisibilities { ref map } = *self;
         map.hash_stable(hcx, hasher);
     }
 }
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index 95e52e391d8..23c2ce6474c 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -43,7 +43,7 @@ pub trait PointerArithmetic: HasDataLayout {
         let val = val as i64;
         // Now wrap-around into the machine_isize range.
         if val > self.machine_isize_max() {
-            // This can only happen the the ptr size is < 64, so we know max_usize_plus_1 fits into
+            // This can only happen if the ptr size is < 64, so we know max_usize_plus_1 fits into
             // i64.
             debug_assert!(self.pointer_size().bits() < 64);
             let max_usize_plus_1 = 1u128 << self.pointer_size().bits();
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 8f67161420d..473894ac1ca 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -4,7 +4,9 @@ use crate::mir;
 use crate::ty::subst::InternalSubsts;
 use crate::ty::visit::TypeVisitable;
 use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt};
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
+use rustc_session::lint;
 use rustc_span::{Span, DUMMY_SP};
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -51,7 +53,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
         match ty::Instance::resolve_opt_const_arg(
             self, param_env,
-            // FIXME: maybe have a seperate version for resolving mir::UnevaluatedConst?
+            // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst?
             ct.def, ct.substs,
         ) {
             Ok(Some(instance)) => {
@@ -83,7 +85,29 @@ impl<'tcx> TyCtxt<'tcx> {
         match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
             Ok(Some(instance)) => {
                 let cid = GlobalId { instance, promoted: None };
-                self.const_eval_global_id_for_typeck(param_env, cid, span)
+                self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| {
+                    // We are emitting the lint here instead of in `is_const_evaluatable`
+                    // as we normalize obligations before checking them, and normalization
+                    // uses this function to evaluate this constant.
+                    //
+                    // @lcnr believes that successfully evaluating even though there are
+                    // used generic parameters is a bug of evaluation, so checking for it
+                    // here does feel somewhat sensible.
+                    if !self.features().generic_const_exprs && ct.substs.has_non_region_param() {
+                        assert!(matches!(self.def_kind(ct.def.did), DefKind::AnonConst));
+                        let mir_body = self.mir_for_ctfe_opt_const_arg(ct.def);
+                        if mir_body.is_polymorphic {
+                            let Some(local_def_id) = ct.def.did.as_local() else { return };
+                            self.struct_span_lint_hir(
+                                lint::builtin::CONST_EVALUATABLE_UNCHECKED,
+                                self.hir().local_def_id_to_hir_id(local_def_id),
+                                self.def_span(ct.def.did),
+                                "cannot use constants which depend on generic parameters in types",
+                                |err| err,
+                            )
+                        }
+                    }
+                })
             }
             Ok(None) => Err(ErrorHandled::TooGeneric),
             Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index d4258151ff3..068daaadbda 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -7,9 +7,9 @@ use crate::mir::interpret::{
 };
 use crate::mir::visit::MirVisitable;
 use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
 use crate::ty::print::{FmtPrinter, Printer};
-use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use crate::ty::visit::{TypeVisitable, TypeVisitor};
 use crate::ty::{self, List, Ty, TyCtxt};
 use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex};
 use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
@@ -116,11 +116,6 @@ pub trait MirPass<'tcx> {
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
 
-    /// If this pass causes the MIR to enter a new phase, return that phase.
-    fn phase_change(&self) -> Option<MirPhase> {
-        None
-    }
-
     fn is_mir_dump_enabled(&self) -> bool {
         true
     }
@@ -145,6 +140,35 @@ impl MirPhase {
     }
 }
 
+impl Display for MirPhase {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        match self {
+            MirPhase::Built => write!(f, "built"),
+            MirPhase::Analysis(p) => write!(f, "analysis-{}", p),
+            MirPhase::Runtime(p) => write!(f, "runtime-{}", p),
+        }
+    }
+}
+
+impl Display for AnalysisPhase {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        match self {
+            AnalysisPhase::Initial => write!(f, "initial"),
+            AnalysisPhase::PostCleanup => write!(f, "post_cleanup"),
+        }
+    }
+}
+
+impl Display for RuntimePhase {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        match self {
+            RuntimePhase::Initial => write!(f, "initial"),
+            RuntimePhase::PostCleanup => write!(f, "post_cleanup"),
+            RuntimePhase::Optimized => write!(f, "optimized"),
+        }
+    }
+}
+
 /// Where a specific `mir::Body` comes from.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
@@ -207,6 +231,9 @@ pub struct Body<'tcx> {
     /// us to see the difference and forego optimization on the inlined promoted items.
     pub phase: MirPhase,
 
+    /// How many passses we have executed since starting the current phase. Used for debug output.
+    pub pass_count: usize,
+
     pub source: MirSource<'tcx>,
 
     /// A list of source scopes; these are referenced by statements
@@ -292,6 +319,7 @@ impl<'tcx> Body<'tcx> {
 
         let mut body = Body {
             phase: MirPhase::Built,
+            pass_count: 1,
             source,
             basic_blocks: BasicBlocks::new(basic_blocks),
             source_scopes,
@@ -325,6 +353,7 @@ impl<'tcx> Body<'tcx> {
     pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
         let mut body = Body {
             phase: MirPhase::Built,
+            pass_count: 1,
             source: MirSource::item(CRATE_DEF_ID.to_def_id()),
             basic_blocks: BasicBlocks::new(basic_blocks),
             source_scopes: IndexVec::new(),
@@ -1157,6 +1186,11 @@ impl<'tcx> BasicBlockData<'tcx> {
     pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> {
         if index < self.statements.len() { &self.statements[index] } else { &self.terminator }
     }
+
+    /// Does the block have no statements and an unreachable terminator?
+    pub fn is_empty_unreachable(&self) -> bool {
+        self.statements.is_empty() && matches!(self.terminator().kind, TerminatorKind::Unreachable)
+    }
 }
 
 impl<O> AssertKind<O> {
@@ -1824,7 +1858,6 @@ impl<'tcx> Rvalue<'tcx> {
             // While the model is undecided, we should be conservative. See
             // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
             Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
-            Rvalue::Cast(CastKind::DynStar, _, _) => false,
 
             Rvalue::Use(_)
             | Rvalue::CopyForDeref(_)
@@ -1841,7 +1874,8 @@ impl<'tcx> Rvalue<'tcx> {
                 | CastKind::FnPtrToPtr
                 | CastKind::PtrToPtr
                 | CastKind::Pointer(_)
-                | CastKind::PointerFromExposedAddress,
+                | CastKind::PointerFromExposedAddress
+                | CastKind::DynStar,
                 _,
                 _,
             )
@@ -2056,7 +2090,7 @@ pub struct Constant<'tcx> {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
-#[derive(Lift)]
+#[derive(Lift, TypeFoldable, TypeVisitable)]
 pub enum ConstantKind<'tcx> {
     /// This constant came from the type system
     Ty(ty::Const<'tcx>),
@@ -2448,7 +2482,7 @@ impl<'tcx> ConstantKind<'tcx> {
 
 /// An unevaluated (potentially generic) constant used in MIR.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
-#[derive(Hash, HashStable)]
+#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub struct UnevaluatedConst<'tcx> {
     pub def: ty::WithOptConstParam<DefId>,
     pub substs: SubstsRef<'tcx>,
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index fdda62719ee..15a24aa4ace 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -81,7 +81,7 @@ impl<'tcx> MonoItem<'tcx> {
             MonoItem::Fn(instance) => tcx.symbol_name(instance),
             MonoItem::Static(def_id) => tcx.symbol_name(Instance::mono(tcx, def_id)),
             MonoItem::GlobalAsm(item_id) => {
-                SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.def_id))
+                SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.owner_id))
             }
         }
     }
@@ -182,7 +182,7 @@ impl<'tcx> MonoItem<'tcx> {
         match *self {
             MonoItem::Fn(Instance { def, .. }) => def.def_id().as_local(),
             MonoItem::Static(def_id) => def_id.as_local(),
-            MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.def_id),
+            MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id),
         }
         .map(|def_id| tcx.def_span(def_id))
     }
@@ -373,7 +373,7 @@ impl<'tcx> CodegenUnit<'tcx> {
                         }
                     }
                     MonoItem::Static(def_id) => def_id.as_local().map(Idx::index),
-                    MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.def_id.index()),
+                    MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id.index()),
                 },
                 item.symbol_name(tcx),
             )
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 8e18cad442e..4c0974f86fb 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -3,7 +3,6 @@
 use rustc_ast::InlineAsmTemplatePiece;
 
 use super::*;
-use crate::mir;
 use crate::ty;
 
 TrivialTypeTraversalAndLiftImpls! {
@@ -27,6 +26,12 @@ TrivialTypeTraversalAndLiftImpls! {
     GeneratorSavedLocal,
 }
 
+TrivialTypeTraversalImpls! {
+    for <'tcx> {
+        ConstValue<'tcx>,
+    }
+}
+
 impl<'tcx> TypeFoldable<'tcx> for &'tcx [InlineAsmTemplatePiece] {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
         Ok(self)
@@ -50,44 +55,3 @@ impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
         Ok(self)
     }
 }
-
-impl<'tcx> TypeFoldable<'tcx> for mir::UnevaluatedConst<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        folder.try_fold_mir_unevaluated(self)
-    }
-}
-
-impl<'tcx> TypeSuperFoldable<'tcx> for mir::UnevaluatedConst<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        Ok(mir::UnevaluatedConst {
-            def: self.def,
-            substs: self.substs.try_fold_with(folder)?,
-            promoted: self.promoted,
-        })
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
-    #[inline(always)]
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        folder.try_fold_mir_const(self)
-    }
-}
-
-impl<'tcx> TypeSuperFoldable<'tcx> for ConstantKind<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        match self {
-            ConstantKind::Ty(c) => Ok(ConstantKind::Ty(c.try_fold_with(folder)?)),
-            ConstantKind::Val(v, t) => Ok(ConstantKind::Val(v, t.try_fold_with(folder)?)),
-            ConstantKind::Unevaluated(uv, t) => {
-                Ok(ConstantKind::Unevaluated(uv.try_fold_with(folder)?, t.try_fold_with(folder)?))
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_middle/src/mir/type_visitable.rs b/compiler/rustc_middle/src/mir/type_visitable.rs
index a136ca4d8c3..e7cd497b206 100644
--- a/compiler/rustc_middle/src/mir/type_visitable.rs
+++ b/compiler/rustc_middle/src/mir/type_visitable.rs
@@ -1,41 +1,9 @@
 //! `TypeVisitable` implementations for MIR types
 
 use super::*;
-use crate::mir;
 
 impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix<R, C> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
-
-impl<'tcx> TypeVisitable<'tcx> for mir::UnevaluatedConst<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        visitor.visit_mir_unevaluated(*self)
-    }
-}
-
-impl<'tcx> TypeSuperVisitable<'tcx> for mir::UnevaluatedConst<'tcx> {
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.substs.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for ConstantKind<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        visitor.visit_mir_const(*self)
-    }
-}
-
-impl<'tcx> TypeSuperVisitable<'tcx> for ConstantKind<'tcx> {
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        match *self {
-            ConstantKind::Ty(c) => c.visit_with(visitor),
-            ConstantKind::Val(_, t) => t.visit_with(visitor),
-            ConstantKind::Unevaluated(uv, t) => {
-                uv.visit_with(visitor)?;
-                t.visit_with(visitor)
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 06eb10c9137..33acaed435b 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -4,6 +4,9 @@
 //! ["Queries: demand-driven compilation"](https://rustc-dev-guide.rust-lang.org/query.html).
 //! This chapter includes instructions for adding new queries.
 
+use crate::ty::{self, print::describe_as_module, TyCtxt};
+use rustc_span::def_id::LOCAL_CRATE;
+
 // Each of these queries corresponds to a function pointer field in the
 // `Providers` struct for requesting a value of that type, and a method
 // on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way
@@ -17,19 +20,19 @@
 // as they will raise an fatal error on query cycles instead.
 rustc_queries! {
     query trigger_delay_span_bug(key: DefId) -> () {
-        desc { "trigger a delay span bug" }
+        desc { "triggering a delay span bug" }
     }
 
-    query resolutions(_: ()) -> &'tcx ty::ResolverOutputs {
+    query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt {
         eval_always
         no_hash
-        desc { "get the resolver outputs" }
+        desc { "getting the resolver outputs" }
     }
 
     query resolver_for_lowering(_: ()) -> &'tcx Steal<ty::ResolverAstLowering> {
         eval_always
         no_hash
-        desc { "get the resolver for lowering" }
+        desc { "getting the resolver for lowering" }
     }
 
     /// Return the span for a definition.
@@ -37,7 +40,7 @@ rustc_queries! {
     /// This span is meant for dep-tracking rather than diagnostics. It should not be used outside
     /// of rustc_middle::hir::source_map.
     query source_span(key: LocalDefId) -> Span {
-        desc { "get the source span" }
+        desc { "getting the source span" }
     }
 
     /// Represents crate as a whole (as distinct from the top-level crate module).
@@ -49,14 +52,14 @@ rustc_queries! {
     query hir_crate(key: ()) -> Crate<'tcx> {
         arena_cache
         eval_always
-        desc { "get the crate HIR" }
+        desc { "getting the crate HIR" }
     }
 
     /// All items in the crate.
     query hir_crate_items(_: ()) -> rustc_middle::hir::ModuleItems {
         arena_cache
         eval_always
-        desc { "get HIR crate items" }
+        desc { "getting HIR crate items" }
     }
 
     /// The items in a module.
@@ -65,7 +68,7 @@ rustc_queries! {
     /// Avoid calling this query directly.
     query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems {
         arena_cache
-        desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
         cache_on_disk_if { true }
     }
 
@@ -74,7 +77,7 @@ rustc_queries! {
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
     query hir_owner(key: hir::OwnerId) -> Option<crate::hir::Owner<'tcx>> {
-        desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     /// Gives access to the HIR ID for the given `LocalDefId` owner `key`.
@@ -82,7 +85,7 @@ rustc_queries! {
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
     query local_def_id_to_hir_id(key: LocalDefId) -> hir::HirId {
-        desc { |tcx| "HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     /// Gives access to the HIR node's parent for the HIR owner `key`.
@@ -90,7 +93,7 @@ rustc_queries! {
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
     query hir_owner_parent(key: hir::OwnerId) -> hir::HirId {
-        desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     /// Gives access to the HIR nodes and bodies inside the HIR owner `key`.
@@ -98,7 +101,7 @@ rustc_queries! {
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
     query hir_owner_nodes(key: hir::OwnerId) -> hir::MaybeOwner<&'tcx hir::OwnerNodes<'tcx>> {
-        desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     /// Gives access to the HIR attributes inside the HIR owner `key`.
@@ -106,7 +109,7 @@ rustc_queries! {
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
     query hir_attrs(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> {
-        desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     /// Computes the `DefId` of the corresponding const parameter in case the `key` is a
@@ -135,7 +138,7 @@ rustc_queries! {
     /// Given the def_id of a const-generic parameter, computes the associated default const
     /// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
     query const_param_default(param: DefId) -> ty::Const<'tcx> {
-        desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param)  }
+        desc { |tcx| "computing const default for a given parameter `{}`", tcx.def_path_str(param)  }
         cache_on_disk_if { param.is_local() }
         separate_provide_extern
     }
@@ -164,7 +167,7 @@ rustc_queries! {
     query collect_trait_impl_trait_tys(key: DefId)
         -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>
     {
-        desc { "compare an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
+        desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
@@ -287,11 +290,11 @@ rustc_queries! {
 
     query parent_module_from_def_id(key: LocalDefId) -> LocalDefId {
         eval_always
-        desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting the parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
-        desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
+        desc { |tcx| "getting the expansion that defined `{}`", tcx.def_path_str(key) }
         separate_provide_extern
     }
 
@@ -303,7 +306,7 @@ rustc_queries! {
 
     /// Checks whether a type is representable or infinitely sized
     query representability(_: LocalDefId) -> rustc_middle::ty::Representability {
-        desc { "checking if {:?} is representable", tcx.def_path_str(key.to_def_id()) }
+        desc { "checking if `{}` is representable", tcx.def_path_str(key.to_def_id()) }
         // infinitely sized types will cause a cycle
         cycle_delay_bug
         // we don't want recursive representability calls to be forced with
@@ -314,7 +317,7 @@ rustc_queries! {
 
     /// An implementation detail for the `representability` query
     query representability_adt_ty(_: Ty<'tcx>) -> rustc_middle::ty::Representability {
-        desc { "checking if {:?} is representable", key }
+        desc { "checking if `{}` is representable", key }
         cycle_delay_bug
         anon
     }
@@ -380,7 +383,7 @@ rustc_queries! {
     /// See the README for the `mir` module for details.
     query mir_const(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
         desc {
-            |tcx| "processing MIR for {}`{}`",
+            |tcx| "preparing {}`{}` for borrow checking",
             if key.const_param_did.is_some() { "the const argument " } else { "" },
             tcx.def_path_str(key.did.to_def_id()),
         }
@@ -392,7 +395,7 @@ rustc_queries! {
         key: DefId
     ) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
         desc {
-            |tcx| "building an abstract representation for {}", tcx.def_path_str(key),
+            |tcx| "building an abstract representation for `{}`", tcx.def_path_str(key),
         }
         separate_provide_extern
     }
@@ -402,7 +405,7 @@ rustc_queries! {
     ) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
         desc {
             |tcx|
-            "building an abstract representation for the const argument {}",
+            "building an abstract representation for the const argument `{}`",
             tcx.def_path_str(key.0.to_def_id()),
         }
     }
@@ -411,7 +414,7 @@ rustc_queries! {
         ty::ParamEnvAnd<'tcx, (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>
     )>) -> bool {
         desc {
-            |tcx| "trying to unify the generic constants {} and {}",
+            |tcx| "trying to unify the generic constants `{}` and `{}`",
             tcx.def_path_str(key.value.0.def.did), tcx.def_path_str(key.value.1.def.did)
         }
     }
@@ -433,7 +436,7 @@ rustc_queries! {
 
     query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
         desc {
-            |tcx| "MIR for CTFE of the const argument `{}`",
+            |tcx| "caching MIR for CTFE of the const argument `{}`",
             tcx.def_path_str(key.0.to_def_id())
         }
     }
@@ -445,7 +448,7 @@ rustc_queries! {
         ) {
         no_hash
         desc {
-            |tcx| "processing {}`{}`",
+            |tcx| "processing MIR for {}`{}`",
             if key.const_param_did.is_some() { "the const argument " } else { "" },
             tcx.def_path_str(key.did.to_def_id()),
         }
@@ -456,7 +459,7 @@ rustc_queries! {
     ) -> Vec<rustc_span::Symbol> {
         arena_cache
         desc {
-            |tcx| "symbols for captures of closure `{}` in `{}`",
+            |tcx| "finding symbols for captures of closure `{}` in `{}`",
             tcx.def_path_str(key.1.to_def_id()),
             tcx.def_path_str(key.0.to_def_id())
         }
@@ -518,12 +521,12 @@ rustc_queries! {
         // queries). Making it anonymous avoids hashing the result, which
         // may save a bit of time.
         anon
-        desc { "erasing regions from `{:?}`", ty }
+        desc { "erasing regions from `{}`", ty }
     }
 
     query wasm_import_module_map(_: CrateNum) -> FxHashMap<DefId, String> {
         arena_cache
-        desc { "wasm import module map" }
+        desc { "getting wasm import module map" }
     }
 
     /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
@@ -703,7 +706,7 @@ rustc_queries! {
     /// Collects the associated items defined on a trait or impl.
     query associated_items(key: DefId) -> ty::AssocItems<'tcx> {
         arena_cache
-        desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
+        desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
     }
 
     /// Maps from associated items on a trait to the corresponding associated
@@ -729,7 +732,7 @@ rustc_queries! {
     ///`{ trait_f: impl_f, trait_g: impl_g }`
     query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> {
         arena_cache
-        desc { |tcx| "comparing impl items against trait for {}", tcx.def_path_str(impl_id) }
+        desc { |tcx| "comparing impl items against trait for `{}`", tcx.def_path_str(impl_id) }
     }
 
     /// Given an `impl_id`, return the trait it implements.
@@ -801,7 +804,7 @@ rustc_queries! {
     /// Note that we've liberated the late bound regions of function signatures, so
     /// this can not be used to check whether these types are well formed.
     query assumed_wf_types(key: DefId) -> &'tcx ty::List<Ty<'tcx>> {
-        desc { |tcx| "computing the implied bounds of {}", tcx.def_path_str(key) }
+        desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
     }
 
     /// Computes the signature of the function.
@@ -850,7 +853,7 @@ rustc_queries! {
     }
 
     query check_liveness(key: DefId) {
-        desc { |tcx| "checking liveness of variables in {}", tcx.def_path_str(key) }
+        desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key) }
     }
 
     /// Return the live symbols in the crate for dead code check.
@@ -862,7 +865,7 @@ rustc_queries! {
         FxHashMap<LocalDefId, Vec<(DefId, DefId)>>
     ) {
         arena_cache
-        desc { "find live symbols in crate" }
+        desc { "finding live symbols in crate" }
     }
 
     query check_mod_deathness(key: LocalDefId) -> () {
@@ -909,8 +912,8 @@ rustc_queries! {
         cache_on_disk_if { true }
     }
 
-    query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet<LocalDefId> {
-        desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
+    query used_trait_imports(key: LocalDefId) -> &'tcx UnordSet<LocalDefId> {
+        desc { |tcx| "finding used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
         cache_on_disk_if { true }
     }
 
@@ -939,7 +942,7 @@ rustc_queries! {
     /// Not meant to be used directly outside of coherence.
     query crate_inherent_impls(k: ()) -> CrateInherentImpls {
         arena_cache
-        desc { "all inherent impls defined in crate" }
+        desc { "finding all inherent impls defined in crate" }
     }
 
     /// Checks all types in the crate for overlap in their inherent impls. Reports errors.
@@ -1029,7 +1032,7 @@ rustc_queries! {
     query try_destructure_mir_constant(
         key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
     ) -> Option<mir::DestructuredConstant<'tcx>> {
-        desc { "destructuring mir constant"}
+        desc { "destructuring MIR constant"}
         remap_env_constness
     }
 
@@ -1038,12 +1041,12 @@ rustc_queries! {
     query deref_mir_constant(
         key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
     ) -> mir::ConstantKind<'tcx> {
-        desc { "dereferencing mir constant" }
+        desc { "dereferencing MIR constant" }
         remap_env_constness
     }
 
     query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
-        desc { "get a &core::panic::Location referring to a span" }
+        desc { "getting a &core::panic::Location referring to a span" }
     }
 
     // FIXME get rid of this with valtrees
@@ -1062,10 +1065,10 @@ rustc_queries! {
         cache_on_disk_if { key.is_local() }
     }
 
-    /// Performs part of the privacy check and computes "access levels".
-    query privacy_access_levels(_: ()) -> &'tcx AccessLevels {
+    /// Performs part of the privacy check and computes effective visibilities.
+    query effective_visibilities(_: ()) -> &'tcx EffectiveVisibilities {
         eval_always
-        desc { "privacy access levels" }
+        desc { "checking effective visibilities" }
     }
     query check_private_in_public(_: ()) -> () {
         eval_always
@@ -1193,29 +1196,29 @@ rustc_queries! {
     }
 
     query is_ctfe_mir_available(key: DefId) -> bool {
-        desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
+        desc { |tcx| "checking if item has CTFE MIR available: `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
     query is_mir_available(key: DefId) -> bool {
-        desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
+        desc { |tcx| "checking if item has MIR available: `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
     query own_existential_vtable_entries(
-        key: ty::PolyExistentialTraitRef<'tcx>
+        key: DefId
     ) -> &'tcx [DefId] {
-        desc { |tcx| "finding all existential vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
+        desc { |tcx| "finding all existential vtable entries for trait `{}`", tcx.def_path_str(key) }
     }
 
     query vtable_entries(key: ty::PolyTraitRef<'tcx>)
                         -> &'tcx [ty::VtblEntry<'tcx>] {
-        desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
+        desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id()) }
     }
 
-    query vtable_trait_upcasting_coercion_new_vptr_slot(key: (ty::Ty<'tcx>, ty::Ty<'tcx>)) -> Option<usize> {
-        desc { |tcx| "finding the slot within vtable for trait object {} vtable ptr during trait upcasting coercion from {} vtable",
+    query vtable_trait_upcasting_coercion_new_vptr_slot(key: (Ty<'tcx>, Ty<'tcx>)) -> Option<usize> {
+        desc { |tcx| "finding the slot within vtable for trait object `{}` vtable ptr during trait upcasting coercion from `{}` vtable",
             key.1, key.0 }
     }
 
@@ -1235,13 +1238,13 @@ rustc_queries! {
 
     /// Return all `impl` blocks in the current crate.
     query all_local_trait_impls(_: ()) -> &'tcx rustc_data_structures::fx::FxIndexMap<DefId, Vec<LocalDefId>> {
-        desc { "local trait impls" }
+        desc { "finding local trait impls" }
     }
 
     /// Given a trait `trait_id`, return all known `impl` blocks.
     query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls {
         arena_cache
-        desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) }
+        desc { |tcx| "finding trait impls of `{}`", tcx.def_path_str(trait_id) }
     }
 
     query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph {
@@ -1250,7 +1253,7 @@ rustc_queries! {
         cache_on_disk_if { true }
     }
     query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
-        desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) }
+        desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) }
     }
 
     /// Gets the ParameterEnvironment for a given item; this environment
@@ -1308,7 +1311,7 @@ rustc_queries! {
     /// correctly.
     query has_structural_eq_impls(ty: Ty<'tcx>) -> bool {
         desc {
-            "computing whether `{:?}` implements `PartialStructuralEq` and `StructuralEq`",
+            "computing whether `{}` implements `PartialStructuralEq` and `StructuralEq`",
             ty
         }
     }
@@ -1367,13 +1370,13 @@ rustc_queries! {
 
     query dylib_dependency_formats(_: CrateNum)
                                     -> &'tcx [(CrateNum, LinkagePreference)] {
-        desc { "dylib dependency formats of crate" }
+        desc { "getting dylib dependency formats of crate" }
         separate_provide_extern
     }
 
     query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
         arena_cache
-        desc { "get the linkage format of all dependencies" }
+        desc { "getting the linkage format of all dependencies" }
     }
 
     query is_compiler_builtins(_: CrateNum) -> bool {
@@ -1388,6 +1391,13 @@ rustc_queries! {
         desc { "checking if the crate has_global_allocator" }
         separate_provide_extern
     }
+    query has_alloc_error_handler(_: CrateNum) -> bool {
+        // This query depends on untracked global state in CStore
+        eval_always
+        fatal_cycle
+        desc { "checking if the crate has_alloc_error_handler" }
+        separate_provide_extern
+    }
     query has_panic_handler(_: CrateNum) -> bool {
         fatal_cycle
         desc { "checking if the crate has_panic_handler" }
@@ -1395,31 +1405,31 @@ rustc_queries! {
     }
     query is_profiler_runtime(_: CrateNum) -> bool {
         fatal_cycle
-        desc { "query a crate is `#![profiler_runtime]`" }
+        desc { "checking if a crate is `#![profiler_runtime]`" }
         separate_provide_extern
     }
     query has_ffi_unwind_calls(key: LocalDefId) -> bool {
-        desc { |tcx| "check if `{}` contains FFI-unwind calls", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "checking if `{}` contains FFI-unwind calls", tcx.def_path_str(key.to_def_id()) }
         cache_on_disk_if { true }
     }
     query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
         fatal_cycle
-        desc { "query a crate's required panic strategy" }
+        desc { "getting a crate's required panic strategy" }
         separate_provide_extern
     }
     query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy {
         fatal_cycle
-        desc { "query a crate's configured panic-in-drop strategy" }
+        desc { "getting a crate's configured panic-in-drop strategy" }
         separate_provide_extern
     }
     query is_no_builtins(_: CrateNum) -> bool {
         fatal_cycle
-        desc { "test whether a crate has `#![no_builtins]`" }
+        desc { "getting whether a crate has `#![no_builtins]`" }
         separate_provide_extern
     }
     query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion {
         fatal_cycle
-        desc { "query a crate's symbol mangling version" }
+        desc { "getting a crate's symbol mangling version" }
         separate_provide_extern
     }
 
@@ -1434,7 +1444,7 @@ rustc_queries! {
     }
     query in_scope_traits_map(_: hir::OwnerId)
         -> Option<&'tcx FxHashMap<ItemLocalId, Box<[TraitCandidate]>>> {
-        desc { "traits in scope at a block" }
+        desc { "getting traits in scope at a block" }
     }
 
     query module_reexports(def_id: LocalDefId) -> Option<&'tcx [ModChild]> {
@@ -1584,18 +1594,8 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query is_dllimport_foreign_item(def_id: DefId) -> bool {
-        desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
-    }
-    query is_statically_included_foreign_item(def_id: DefId) -> bool {
-        desc { |tcx| "is_statically_included_foreign_item({})", tcx.def_path_str(def_id) }
-    }
-    query native_library_kind(def_id: DefId)
-        -> Option<NativeLibKind> {
-        desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) }
-    }
     query native_library(def_id: DefId) -> Option<&'tcx NativeLib> {
-        desc { |tcx| "native_library({})", tcx.def_path_str(def_id) }
+        desc { |tcx| "getting the native library for `{}`", tcx.def_path_str(def_id) }
     }
 
     /// Does lifetime resolution, but does not descend into trait items. This
@@ -1650,14 +1650,13 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    /// Computes the set of modules from which this type is visibly uninhabited.
-    /// To check whether a type is uninhabited at all (not just from a given module), you could
-    /// check whether the forest is empty.
-    query type_uninhabited_from(
-        key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
-    ) -> ty::inhabitedness::DefIdForest<'tcx> {
-        desc { "computing the inhabitedness of `{:?}`", key }
-        remap_env_constness
+    query inhabited_predicate_adt(key: DefId) -> ty::inhabitedness::InhabitedPredicate<'tcx> {
+        desc { "computing the uninhabited predicate of `{:?}`", key }
+    }
+
+    /// Do not call this query directly: invoke `Ty::inhabited_predicate` instead.
+    query inhabited_predicate_type(key: Ty<'tcx>) -> ty::inhabitedness::InhabitedPredicate<'tcx> {
+        desc { "computing the uninhabited predicate of `{}`", key }
     }
 
     query dep_kind(_: CrateNum) -> CrateDepKind {
@@ -1695,7 +1694,7 @@ rustc_queries! {
     }
     /// Whether the function is an intrinsic
     query is_intrinsic(def_id: DefId) -> bool {
-        desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) }
+        desc { |tcx| "checking whether `{}` is an intrinsic", tcx.def_path_str(def_id) }
         separate_provide_extern
     }
     /// Returns the lang items defined in another crate by loading it from metadata.
@@ -1713,7 +1712,7 @@ rustc_queries! {
     }
 
     /// Returns the lang items defined in another crate by loading it from metadata.
-    query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] {
+    query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, LangItem)] {
         desc { "calculating the lang items defined in a crate" }
         separate_provide_extern
     }
@@ -1762,12 +1761,16 @@ rustc_queries! {
     /// is marked as a private dependency
     query is_private_dep(c: CrateNum) -> bool {
         eval_always
-        desc { "check whether crate {} is a private dependency", c }
+        desc { "checking whether crate `{}` is a private dependency", c }
         separate_provide_extern
     }
     query allocator_kind(_: ()) -> Option<AllocatorKind> {
         eval_always
-        desc { "allocator kind for the current crate" }
+        desc { "getting the allocator kind for the current crate" }
+    }
+    query alloc_error_handler_kind(_: ()) -> Option<AllocatorKind> {
+        eval_always
+        desc { "alloc error handler kind for the current crate" }
     }
 
     query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
@@ -1780,7 +1783,7 @@ rustc_queries! {
         desc { "looking up all possibly unused extern crates" }
     }
     query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxHashSet<Symbol> {
-        desc { |tcx| "names_imported_by_glob_use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
+        desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
     }
 
     query stability_index(_: ()) -> stability::Index {
@@ -1806,7 +1809,7 @@ rustc_queries! {
     ///   correspond to a publicly visible symbol in `cnum` machine code.
     /// - The `exported_symbols` sets of different crates do not intersect.
     query exported_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
-        desc { "exported_symbols" }
+        desc { "collecting exported symbols for crate `{}`", cnum}
         cache_on_disk_if { *cnum == LOCAL_CRATE }
         separate_provide_extern
     }
@@ -1815,6 +1818,7 @@ rustc_queries! {
         eval_always
         desc { "collect_and_partition_mono_items" }
     }
+
     query is_codegened_item(def_id: DefId) -> bool {
         desc { |tcx| "determining whether `{}` needs codegen", tcx.def_path_str(def_id) }
     }
@@ -1822,12 +1826,13 @@ rustc_queries! {
     /// All items participating in code generation together with items inlined into them.
     query codegened_and_inlined_items(_: ()) -> &'tcx DefIdSet {
         eval_always
-       desc { "codegened_and_inlined_items" }
+        desc { "collecting codegened and inlined items" }
     }
 
-    query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
-        desc { "codegen_unit" }
+    query codegen_unit(sym: Symbol) -> &'tcx CodegenUnit<'tcx> {
+        desc { "getting codegen unit `{sym}`" }
     }
+
     query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> {
         cache_on_disk_if { key.def_id().is_local() }
         desc {
@@ -1836,6 +1841,7 @@ rustc_queries! {
         }
         separate_provide_extern
     }
+
     query backend_optimization_level(_: ()) -> OptLevel {
         desc { "optimization level used by backend" }
     }
@@ -1846,7 +1852,7 @@ rustc_queries! {
     /// has been destroyed.
     query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
         eval_always
-        desc { "output_filenames" }
+        desc { "getting output filenames" }
     }
 
     /// Do not call this query directly: invoke `normalize` instead.
@@ -1856,7 +1862,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
         NoSolution,
     > {
-        desc { "normalizing `{:?}`", goal }
+        desc { "normalizing `{}`", goal.value.value }
         remap_env_constness
     }
 
@@ -1868,21 +1874,13 @@ rustc_queries! {
         remap_env_constness
     }
 
-    /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
-    query try_normalize_mir_const_after_erasing_regions(
-        goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
-    ) -> Result<mir::ConstantKind<'tcx>, NoSolution> {
-        desc { "normalizing `{}`", goal.value }
-        remap_env_constness
-    }
-
     query implied_outlives_bounds(
         goal: CanonicalTyGoal<'tcx>
     ) -> Result<
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
         NoSolution,
     > {
-        desc { "computing implied outlives bounds for `{:?}`", goal }
+        desc { "computing implied outlives bounds for `{}`", goal.value.value }
         remap_env_constness
     }
 
@@ -1894,7 +1892,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>,
         NoSolution,
     > {
-        desc { "computing dropck types for `{:?}`", goal }
+        desc { "computing dropck types for `{}`", goal.value.value }
         remap_env_constness
     }
 
@@ -1922,7 +1920,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
         NoSolution,
     > {
-        desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal }
+        desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal.value.value }
         remap_env_constness
     }
 
@@ -1933,7 +1931,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
         NoSolution,
     > {
-        desc { "evaluating `type_op_eq` `{:?}`", goal }
+        desc { "evaluating `type_op_eq` `{:?}`", goal.value.value }
         remap_env_constness
     }
 
@@ -1944,7 +1942,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
         NoSolution,
     > {
-        desc { "evaluating `type_op_subtype` `{:?}`", goal }
+        desc { "evaluating `type_op_subtype` `{:?}`", goal.value.value }
         remap_env_constness
     }
 
@@ -1955,7 +1953,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
         NoSolution,
     > {
-        desc { "evaluating `type_op_prove_predicate` `{:?}`", goal }
+        desc { "evaluating `type_op_prove_predicate` `{:?}`", goal.value.value }
     }
 
     /// Do not call this query directly: part of the `Normalize` type-op
@@ -1965,7 +1963,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>,
         NoSolution,
     > {
-        desc { "normalizing `{:?}`", goal }
+        desc { "normalizing `{}`", goal.value.value.value }
         remap_env_constness
     }
 
@@ -1976,7 +1974,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>,
         NoSolution,
     > {
-        desc { "normalizing `{:?}`", goal }
+        desc { "normalizing `{:?}`", goal.value.value.value }
         remap_env_constness
     }
 
@@ -1987,7 +1985,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>,
         NoSolution,
     > {
-        desc { "normalizing `{:?}`", goal }
+        desc { "normalizing `{:?}`", goal.value.value.value }
         remap_env_constness
     }
 
@@ -1998,20 +1996,20 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>,
         NoSolution,
     > {
-        desc { "normalizing `{:?}`", goal }
+        desc { "normalizing `{:?}`", goal.value.value.value }
         remap_env_constness
     }
 
     query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
         desc { |tcx|
-            "impossible substituted predicates:`{}`",
+            "checking impossible substituted predicates: `{}`",
             tcx.def_path_str(key.0)
         }
     }
 
     query is_impossible_method(key: (DefId, DefId)) -> bool {
         desc { |tcx|
-            "checking if {} is impossible to call within {}",
+            "checking if `{}` is impossible to call within `{}`",
             tcx.def_path_str(key.1),
             tcx.def_path_str(key.0),
         }
@@ -2020,7 +2018,7 @@ rustc_queries! {
     query method_autoderef_steps(
         goal: CanonicalTyGoal<'tcx>
     ) -> MethodAutoderefStepsResult<'tcx> {
-        desc { "computing autoderef types for `{:?}`", goal }
+        desc { "computing autoderef types for `{}`", goal.value.value }
         remap_env_constness
     }
 
@@ -2068,7 +2066,7 @@ rustc_queries! {
     }
 
     query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
-        desc { "normalizing opaque types in {:?}", key }
+        desc { "normalizing opaque types in `{:?}`", key }
     }
 
     /// Checks whether a type is definitely uninhabited. This is
@@ -2078,7 +2076,7 @@ rustc_queries! {
     /// will be `Abi::Uninhabited`. (Note that uninhabited types may have nonzero
     /// size, to account for partial initialisation. See #49298 for details.)
     query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
-        desc { "conservatively checking if {:?} is privately uninhabited", key }
+        desc { "conservatively checking if `{}` is privately uninhabited", key.value }
         remap_env_constness
     }
 
@@ -2098,7 +2096,7 @@ rustc_queries! {
         arena_cache
         eval_always
         no_hash
-        desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 }
+        desc { "performing HIR wf-checking for predicate `{:?}` at item `{:?}`", key.0, key.1 }
     }
 
 
@@ -2117,11 +2115,11 @@ rustc_queries! {
     }
 
     query permits_uninit_init(key: TyAndLayout<'tcx>) -> bool {
-        desc { "checking to see if {:?} permits being left uninit", key.ty }
+        desc { "checking to see if `{}` permits being left uninit", key.ty }
     }
 
     query permits_zero_init(key: TyAndLayout<'tcx>) -> bool {
-        desc { "checking to see if {:?} permits being left zeroed", key.ty }
+        desc { "checking to see if `{}` permits being left zeroed", key.ty }
     }
 
     query compare_assoc_const_impl_item_with_trait_item(
@@ -2129,4 +2127,9 @@ rustc_queries! {
     ) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0.to_def_id()) }
     }
+
+    query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] {
+        desc { |tcx| "deducing parameter attributes for {}", tcx.def_path_str(def_id) }
+        separate_provide_extern
+    }
 }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index a635e0463e5..e73d44bbb36 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -598,11 +598,6 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
 ///     // type parameters, ImplSource will carry resolutions for those as well:
 ///     concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
 ///
-///     // Case A: ImplSource points at a specific impl. Only possible when
-///     // type is concretely known. If the impl itself has bounded
-///     // type parameters, ImplSource will carry resolutions for those as well:
-///     concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
-///
 ///     // Case B: ImplSource must be provided by caller. This applies when
 ///     // type is a type parameter.
 ///     param.clone();    // ImplSource::Param
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index 0a2819feecf..cccedc9ec6e 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -1,3 +1,4 @@
+use crate::error::StrictCoherenceNeedsNegativeCoherence;
 use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::visit::TypeVisitable;
 use crate::ty::{self, TyCtxt};
@@ -65,9 +66,21 @@ impl OverlapMode {
 
         if with_negative_coherence {
             if strict_coherence { OverlapMode::Strict } else { OverlapMode::WithNegative }
-        } else if strict_coherence {
-            bug!("To use strict_coherence you need to set with_negative_coherence feature flag");
         } else {
+            if strict_coherence {
+                let attr_span = trait_id
+                    .as_local()
+                    .into_iter()
+                    .flat_map(|local_def_id| {
+                        tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(local_def_id))
+                    })
+                    .find(|attr| attr.has_name(sym::rustc_strict_coherence))
+                    .map(|attr| attr.span);
+                tcx.sess.emit_err(StrictCoherenceNeedsNegativeCoherence {
+                    span: tcx.def_span(trait_id),
+                    attr_span,
+                });
+            }
             OverlapMode::Stable
         }
     }
@@ -249,7 +262,7 @@ pub fn ancestors<'tcx>(
 
     if let Some(reported) = specialization_graph.has_errored {
         Err(reported)
-    } else if let Some(reported) = tcx.type_of(start_from_impl).error_reported() {
+    } else if let Err(reported) = tcx.type_of(start_from_impl).error_reported() {
         Err(reported)
     } else {
         Ok(Ancestors {
diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs
index 1aa4df77800..e5bcd5fb27a 100644
--- a/compiler/rustc_middle/src/ty/abstract_const.rs
+++ b/compiler/rustc_middle/src/ty/abstract_const.rs
@@ -1,7 +1,7 @@
 //! A subset of a mir body used for const evaluatability checking.
 use crate::mir;
 use crate::ty::visit::TypeVisitable;
-use crate::ty::{self, DelaySpanBugEmitted, EarlyBinder, SubstsRef, Ty, TyCtxt};
+use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
 use std::cmp;
@@ -43,7 +43,7 @@ impl<'tcx> AbstractConst<'tcx> {
     ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
         match ct.kind() {
             ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv),
-            ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => Err(reported),
+            ty::ConstKind::Error(reported) => Err(reported),
             _ => Ok(None),
         }
     }
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index b809f176760..4682ac96b52 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -101,6 +101,9 @@ pub enum Adjust<'tcx> {
     Borrow(AutoBorrow<'tcx>),
 
     Pointer(PointerCast),
+
+    /// Cast into a dyn* object.
+    DynStar,
 }
 
 /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 51137c52659..14ec88b7e0d 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -455,6 +455,7 @@ impl_arena_copy_decoder! {<'tcx>
     rustc_span::def_id::DefId,
     rustc_span::def_id::LocalDefId,
     (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo),
+    ty::DeducedParamAttrs,
 }
 
 #[macro_export]
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 315e3794f15..f998e608344 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -263,6 +263,10 @@ impl<'tcx> Const<'tcx> {
         self.try_eval_usize(tcx, param_env)
             .unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
     }
+
+    pub fn is_ct_infer(self) -> bool {
+        matches!(self.kind(), ty::ConstKind::Infer(_))
+    }
 }
 
 pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Const<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index c444ec23563..c1c613f6c60 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -5,6 +5,7 @@ use crate::mir::interpret::{AllocId, ConstValue, Scalar};
 use crate::ty::subst::{InternalSubsts, SubstsRef};
 use crate::ty::ParamEnv;
 use crate::ty::{self, TyCtxt, TypeVisitable};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
@@ -14,7 +15,7 @@ use super::ScalarInt;
 
 /// An unevaluated (potentially generic) constant used in the type-system.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
-#[derive(Hash, HashStable)]
+#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub struct UnevaluatedConst<'tcx> {
     pub def: ty::WithOptConstParam<DefId>,
     pub substs: SubstsRef<'tcx>,
@@ -68,7 +69,7 @@ pub enum ConstKind<'tcx> {
 
     /// A placeholder for a const which could not be computed; this is
     /// propagated to avoid useless error messages.
-    Error(ty::DelaySpanBugEmitted),
+    Error(ErrorGuaranteed),
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@@ -108,7 +109,6 @@ impl<'tcx> ConstKind<'tcx> {
 
 /// An inference variable for a const, for use in const generics.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
-#[derive(HashStable)]
 pub enum InferConst<'tcx> {
     /// Infer the value of the const.
     Var(ty::ConstVid<'tcx>),
@@ -116,6 +116,15 @@ pub enum InferConst<'tcx> {
     Fresh(u32),
 }
 
+impl<CTX> HashStable<CTX> for InferConst<'_> {
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        match self {
+            InferConst::Var(_) => panic!("const variables should not be hashed: {self:?}"),
+            InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
+        }
+    }
+}
+
 enum EvalMode {
     Typeck,
     Mir,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 97646003e73..fc3b0716849 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -34,6 +34,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal};
+use rustc_data_structures::unord::UnordSet;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::{
     DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
@@ -56,7 +57,6 @@ use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_session::config::{CrateType, OutputFilenames};
 use rustc_session::cstore::CrateStoreDyn;
-use rustc_session::errors::TargetDataLayoutErrorsWrapper;
 use rustc_session::lint::Lint;
 use rustc_session::Limit;
 use rustc_session::Session;
@@ -80,7 +80,7 @@ use std::mem;
 use std::ops::{Bound, Deref};
 use std::sync::Arc;
 
-use super::{ImplPolarity, RvalueScopes};
+use super::{ImplPolarity, ResolverOutputs, RvalueScopes};
 
 pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
     /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
@@ -117,7 +117,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type BoundTy = ty::BoundTy;
     type PlaceholderType = ty::PlaceholderType;
     type InferTy = InferTy;
-    type DelaySpanBugEmitted = DelaySpanBugEmitted;
+    type ErrorGuaranteed = ErrorGuaranteed;
     type PredicateKind = ty::PredicateKind<'tcx>;
     type AllocId = crate::mir::interpret::AllocId;
 
@@ -128,15 +128,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type PlaceholderRegion = ty::PlaceholderRegion;
 }
 
-/// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s
-/// except through the error-reporting functions on a [`tcx`][TyCtxt].
-#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
-#[derive(TyEncodable, TyDecodable, HashStable)]
-pub struct DelaySpanBugEmitted {
-    pub reported: ErrorGuaranteed,
-    _priv: (),
-}
-
 type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
 
 pub struct CtxtInterners<'tcx> {
@@ -199,9 +190,9 @@ impl<'tcx> CtxtInterners<'tcx> {
                 .intern(kind, |kind| {
                     let flags = super::flags::FlagComputation::for_kind(&kind);
 
-                    // It's impossible to hash inference regions (and will ICE), so we don't need to try to cache them.
+                    // It's impossible to hash inference variables (and will ICE), so we don't need to try to cache them.
                     // Without incremental, we rarely stable-hash types, so let's not do it proactively.
-                    let stable_hash = if flags.flags.intersects(TypeFlags::HAS_RE_INFER)
+                    let stable_hash = if flags.flags.intersects(TypeFlags::NEEDS_INFER)
                         || sess.opts.incremental.is_none()
                     {
                         Fingerprint::ZERO
@@ -532,19 +523,17 @@ pub struct TypeckResults<'tcx> {
     /// This is used for warning unused imports. During type
     /// checking, this `Lrc` should not be cloned: it must have a ref-count
     /// of 1 so that we can insert things into the set mutably.
-    pub used_trait_imports: Lrc<FxHashSet<LocalDefId>>,
+    pub used_trait_imports: Lrc<UnordSet<LocalDefId>>,
 
     /// If any errors occurred while type-checking this body,
     /// this field will be set to `Some(ErrorGuaranteed)`.
     pub tainted_by_errors: Option<ErrorGuaranteed>,
 
     /// All the opaque types that have hidden types set
-    /// by this function. For return-position-impl-trait we also store the
-    /// type here, so that mir-borrowck can figure out hidden types,
+    /// 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).
-    /// For type-alias-impl-trait, this map is only used to prevent query cycles,
-    /// so the hidden types are all `None`.
-    pub concrete_opaque_types: VecMap<LocalDefId, Option<Ty<'tcx>>>,
+    pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
 
     /// Tracks the minimum captures required for a closure;
     /// see `MinCaptureInformationMap` for more details.
@@ -1070,10 +1059,9 @@ pub struct GlobalCtxt<'tcx> {
     pub consts: CommonConsts<'tcx>,
 
     definitions: RwLock<Definitions>,
-    cstore: Box<CrateStoreDyn>,
 
     /// Output of the resolver.
-    pub(crate) untracked_resolutions: ty::ResolverOutputs,
+    pub(crate) untracked_resolutions: ty::ResolverGlobalCtxt,
     untracked_resolver_for_lowering: Steal<ty::ResolverAstLowering>,
     /// The entire crate as AST. This field serves as the input for the hir_crate query,
     /// which lowers it from AST to HIR. It must not be read or used by anything else.
@@ -1236,10 +1224,7 @@ impl<'tcx> TyCtxt<'tcx> {
         lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
         arena: &'tcx WorkerLocal<Arena<'tcx>>,
         hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
-        definitions: Definitions,
-        cstore: Box<CrateStoreDyn>,
-        untracked_resolutions: ty::ResolverOutputs,
-        untracked_resolver_for_lowering: ty::ResolverAstLowering,
+        resolver_outputs: ResolverOutputs,
         krate: Lrc<ast::Crate>,
         dep_graph: DepGraph,
         on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
@@ -1248,15 +1233,20 @@ impl<'tcx> TyCtxt<'tcx> {
         crate_name: &str,
         output_filenames: OutputFilenames,
     ) -> GlobalCtxt<'tcx> {
+        let ResolverOutputs {
+            definitions,
+            global_ctxt: untracked_resolutions,
+            ast_lowering: untracked_resolver_for_lowering,
+        } = resolver_outputs;
         let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| {
-            s.emit_fatal(TargetDataLayoutErrorsWrapper(err));
+            s.emit_fatal(err);
         });
         let interners = CtxtInterners::new(arena);
         let common_types = CommonTypes::new(
             &interners,
             s,
             &definitions,
-            &*cstore,
+            &*untracked_resolutions.cstore,
             // This is only used to create a stable hashing context.
             &untracked_resolutions.source_span,
         );
@@ -1271,7 +1261,6 @@ impl<'tcx> TyCtxt<'tcx> {
             interners,
             dep_graph,
             definitions: RwLock::new(definitions),
-            cstore,
             prof: s.prof.clone(),
             types: common_types,
             lifetimes: common_lifetimes,
@@ -1305,7 +1294,7 @@ impl<'tcx> TyCtxt<'tcx> {
     #[track_caller]
     pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty<'tcx> {
         let reported = self.sess.delay_span_bug(span, msg);
-        self.mk_ty(Error(DelaySpanBugEmitted { reported, _priv: () }))
+        self.mk_ty(Error(reported))
     }
 
     /// Like [TyCtxt::ty_error] but for constants.
@@ -1327,10 +1316,7 @@ impl<'tcx> TyCtxt<'tcx> {
         msg: &str,
     ) -> Const<'tcx> {
         let reported = self.sess.delay_span_bug(span, msg);
-        self.mk_const(ty::ConstS {
-            kind: ty::ConstKind::Error(DelaySpanBugEmitted { reported, _priv: () }),
-            ty,
-        })
+        self.mk_const(ty::ConstS { kind: ty::ConstKind::Error(reported), ty })
     }
 
     pub fn consider_optimizing<T: Fn() -> String>(self, msg: T) -> bool {
@@ -1372,7 +1358,7 @@ impl<'tcx> TyCtxt<'tcx> {
         if let Some(id) = id.as_local() {
             self.definitions_untracked().def_key(id)
         } else {
-            self.cstore.def_key(id)
+            self.untracked_resolutions.cstore.def_key(id)
         }
     }
 
@@ -1386,7 +1372,7 @@ impl<'tcx> TyCtxt<'tcx> {
         if let Some(id) = id.as_local() {
             self.definitions_untracked().def_path(id)
         } else {
-            self.cstore.def_path(id)
+            self.untracked_resolutions.cstore.def_path(id)
         }
     }
 
@@ -1396,7 +1382,7 @@ impl<'tcx> TyCtxt<'tcx> {
         if let Some(def_id) = def_id.as_local() {
             self.definitions_untracked().def_path_hash(def_id)
         } else {
-            self.cstore.def_path_hash(def_id)
+            self.untracked_resolutions.cstore.def_path_hash(def_id)
         }
     }
 
@@ -1405,7 +1391,7 @@ impl<'tcx> TyCtxt<'tcx> {
         if crate_num == LOCAL_CRATE {
             self.sess.local_stable_crate_id()
         } else {
-            self.cstore.stable_crate_id(crate_num)
+            self.untracked_resolutions.cstore.stable_crate_id(crate_num)
         }
     }
 
@@ -1416,7 +1402,7 @@ impl<'tcx> TyCtxt<'tcx> {
         if stable_crate_id == self.sess.local_stable_crate_id() {
             LOCAL_CRATE
         } else {
-            self.cstore.stable_crate_id_to_crate_num(stable_crate_id)
+            self.untracked_resolutions.cstore.stable_crate_id_to_crate_num(stable_crate_id)
         }
     }
 
@@ -1435,8 +1421,9 @@ impl<'tcx> TyCtxt<'tcx> {
         } else {
             // If this is a DefPathHash from an upstream crate, let the CrateStore map
             // it to a DefId.
-            let cnum = self.cstore.stable_crate_id_to_crate_num(stable_crate_id);
-            self.cstore.def_path_hash_to_def_id(cnum, hash)
+            let cstore = &*self.untracked_resolutions.cstore;
+            let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id);
+            cstore.def_path_hash_to_def_id(cnum, hash)
         }
     }
 
@@ -1448,7 +1435,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let (crate_name, stable_crate_id) = if def_id.is_local() {
             (self.crate_name, self.sess.local_stable_crate_id())
         } else {
-            let cstore = &self.cstore;
+            let cstore = &*self.untracked_resolutions.cstore;
             (cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate))
         };
 
@@ -1523,7 +1510,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Note that this is *untracked* and should only be used within the query
     /// system if the result is otherwise tracked through queries
     pub fn cstore_untracked(self) -> &'tcx CrateStoreDyn {
-        &*self.cstore
+        &*self.untracked_resolutions.cstore
     }
 
     /// Note that this is *untracked* and should only be used within the query
@@ -1549,7 +1536,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let hcx = StableHashingContext::new(
             self.sess,
             &*definitions,
-            &*self.cstore,
+            &*self.untracked_resolutions.cstore,
             &self.untracked_resolutions.source_span,
         );
         f(hcx)
@@ -2367,7 +2354,7 @@ impl<'tcx> TyCtxt<'tcx> {
             st,
             self.sess,
             &self.definitions.read(),
-            &*self.cstore,
+            &*self.untracked_resolutions.cstore,
             // This is only used to create a stable hashing context.
             &self.untracked_resolutions.source_span,
         )
@@ -2457,7 +2444,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     #[inline]
     pub fn mk_lang_item(self, ty: Ty<'tcx>, item: LangItem) -> Option<Ty<'tcx>> {
-        let def_id = self.lang_items().require(item).ok()?;
+        let def_id = self.lang_items().get(item)?;
         Some(self.mk_generic_adt(def_id, ty))
     }
 
@@ -2826,6 +2813,11 @@ impl<'tcx> TyCtxt<'tcx> {
         })
     }
 
+    /// Emit a lint at the appropriate level for a hir node, with an associated span.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     pub fn struct_span_lint_hir(
         self,
         lint: &'static Lint,
@@ -2851,6 +2843,11 @@ impl<'tcx> TyCtxt<'tcx> {
         self.struct_lint_node(lint, id, decorator.msg(), |diag| decorator.decorate_lint(diag))
     }
 
+    /// Emit a lint at the appropriate level for a hir node.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     pub fn struct_lint_node(
         self,
         lint: &'static Lint,
@@ -2947,6 +2944,21 @@ impl<'tcx> TyCtxtAt<'tcx> {
     }
 }
 
+/// Parameter attributes that can only be determined by examining the body of a function instead
+/// of just its signature.
+///
+/// These can be useful for optimization purposes when a function is directly called. We compute
+/// them and store them into the crate metadata so that downstream crates can make use of them.
+///
+/// Right now, we only have `read_only`, but `no_capture` and `no_alias` might be useful in the
+/// future.
+#[derive(Clone, Copy, PartialEq, Debug, Default, TyDecodable, TyEncodable, HashStable)]
+pub struct DeducedParamAttrs {
+    /// The parameter is marked immutable in the function and contains no `UnsafeCell` (i.e. its
+    /// type is freeze).
+    pub read_only: bool,
+}
+
 // We are comparing types with different invariant lifetimes, so `ptr::eq`
 // won't work for us.
 fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 855917fb828..b8fd01e6a77 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -511,3 +511,11 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
         c.super_visit_with(self)
     }
 }
+
+#[derive(Diagnostic)]
+#[diag(borrowck_const_not_used_in_type_alias)]
+pub(super) struct ConstNotUsedTraitAlias {
+    pub ct: String,
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 3226950e79e..ffdac93bcd0 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -1,4 +1,3 @@
-use crate::mir;
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use crate::ty::visit::TypeVisitable;
 use crate::ty::{self, Ty, TyCtxt, TypeFlags};
@@ -67,8 +66,4 @@ impl<'tcx> TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
             _ => self.tcx.lifetimes.re_erased,
         }
     }
-
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
-        c.super_fold_with(self)
-    }
 }
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 52f16ad88f6..4e6cdb78602 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -872,9 +872,9 @@ fn foo(&self) -> Self::T { String::new() }
                             // FIXME: account for returning some type in a trait fn impl that has
                             // an assoc type as a return type (#72076).
                             if let hir::Defaultness::Default { has_value: true } =
-                                self.impl_defaultness(item.id.def_id)
+                                self.impl_defaultness(item.id.owner_id)
                             {
-                                if self.type_of(item.id.def_id) == found {
+                                if self.type_of(item.id.owner_id) == found {
                                     diag.span_label(
                                         item.span,
                                         "associated type defaults can't be assumed inside the \
@@ -894,7 +894,7 @@ fn foo(&self) -> Self::T { String::new() }
             })) => {
                 for item in &items[..] {
                     if let hir::AssocItemKind::Type = item.kind {
-                        if self.type_of(item.id.def_id) == found {
+                        if self.type_of(item.id.owner_id) == found {
                             diag.span_label(item.span, "expected this associated type");
                             return true;
                         }
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index a6d0678e99d..7201737be65 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -34,12 +34,6 @@ impl FlagComputation {
         result.flags
     }
 
-    pub fn for_unevaluated_const(uv: ty::UnevaluatedConst<'_>) -> TypeFlags {
-        let mut result = FlagComputation::new();
-        result.add_unevaluated_const(uv);
-        result.flags
-    }
-
     fn add_flags(&mut self, flags: TypeFlags) {
         self.flags = self.flags | flags;
     }
@@ -256,7 +250,7 @@ impl FlagComputation {
                 self.add_substs(substs);
             }
             ty::PredicateKind::ConstEvaluatable(uv) => {
-                self.add_unevaluated_const(uv);
+                self.add_const(uv);
             }
             ty::PredicateKind::ConstEquate(expected, found) => {
                 self.add_const(expected);
@@ -289,7 +283,10 @@ impl FlagComputation {
     fn add_const(&mut self, c: ty::Const<'_>) {
         self.add_ty(c.ty());
         match c.kind() {
-            ty::ConstKind::Unevaluated(unevaluated) => self.add_unevaluated_const(unevaluated),
+            ty::ConstKind::Unevaluated(uv) => {
+                self.add_substs(uv.substs);
+                self.add_flags(TypeFlags::HAS_CT_PROJECTION);
+            }
             ty::ConstKind::Infer(infer) => {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
                 match infer {
@@ -313,11 +310,6 @@ impl FlagComputation {
         }
     }
 
-    fn add_unevaluated_const(&mut self, ct: ty::UnevaluatedConst<'_>) {
-        self.add_substs(ct.substs);
-        self.add_flags(TypeFlags::HAS_CT_PROJECTION);
-    }
-
     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
         self.add_substs(projection.substs);
         match projection.term.unpack() {
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index e4234442fae..54f1499eb3d 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -13,8 +13,7 @@
 //!
 //! There are three groups of traits involved in each traversal.
 //! - `TypeFoldable`. This is implemented once for many types, including:
-//!   - Types of interest, for which the the methods delegate to the
-//!     folder.
+//!   - Types of interest, for which the methods delegate to the folder.
 //!   - All other types, including generic containers like `Vec` and `Option`.
 //!     It defines a "skeleton" of how they should be folded.
 //! - `TypeSuperFoldable`. This is implemented only for each type of interest,
@@ -43,7 +42,6 @@
 //!     - ty.super_fold_with(folder)
 //! - u.fold_with(folder)
 //! ```
-use crate::mir;
 use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitable};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::def_id::DefId;
@@ -128,27 +126,9 @@ pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
         c.super_fold_with(self)
     }
 
-    fn fold_ty_unevaluated(
-        &mut self,
-        uv: ty::UnevaluatedConst<'tcx>,
-    ) -> ty::UnevaluatedConst<'tcx> {
-        uv.super_fold_with(self)
-    }
-
-    fn fold_mir_unevaluated(
-        &mut self,
-        uv: mir::UnevaluatedConst<'tcx>,
-    ) -> mir::UnevaluatedConst<'tcx> {
-        uv.super_fold_with(self)
-    }
-
     fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
         p.super_fold_with(self)
     }
-
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
-        bug!("most type folders should not be folding MIR datastructures: {:?}", c)
-    }
 }
 
 /// This trait is implemented for every folding traversal. There is a fold
@@ -182,33 +162,12 @@ pub trait FallibleTypeFolder<'tcx>: Sized {
         c.try_super_fold_with(self)
     }
 
-    fn try_fold_ty_unevaluated(
-        &mut self,
-        c: ty::UnevaluatedConst<'tcx>,
-    ) -> Result<ty::UnevaluatedConst<'tcx>, Self::Error> {
-        c.try_super_fold_with(self)
-    }
-
-    fn try_fold_mir_unevaluated(
-        &mut self,
-        c: mir::UnevaluatedConst<'tcx>,
-    ) -> Result<mir::UnevaluatedConst<'tcx>, Self::Error> {
-        c.try_super_fold_with(self)
-    }
-
     fn try_fold_predicate(
         &mut self,
         p: ty::Predicate<'tcx>,
     ) -> Result<ty::Predicate<'tcx>, Self::Error> {
         p.try_super_fold_with(self)
     }
-
-    fn try_fold_mir_const(
-        &mut self,
-        c: mir::ConstantKind<'tcx>,
-    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
-        bug!("most type folders should not be folding MIR datastructures: {:?}", c)
-    }
 }
 
 // This blanket implementation of the fallible trait for infallible folders
@@ -242,30 +201,9 @@ where
         Ok(self.fold_const(c))
     }
 
-    fn try_fold_ty_unevaluated(
-        &mut self,
-        c: ty::UnevaluatedConst<'tcx>,
-    ) -> Result<ty::UnevaluatedConst<'tcx>, !> {
-        Ok(self.fold_ty_unevaluated(c))
-    }
-
-    fn try_fold_mir_unevaluated(
-        &mut self,
-        c: mir::UnevaluatedConst<'tcx>,
-    ) -> Result<mir::UnevaluatedConst<'tcx>, !> {
-        Ok(self.fold_mir_unevaluated(c))
-    }
-
     fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
         Ok(self.fold_predicate(p))
     }
-
-    fn try_fold_mir_const(
-        &mut self,
-        c: mir::ConstantKind<'tcx>,
-    ) -> Result<mir::ConstantKind<'tcx>, !> {
-        Ok(self.fold_mir_const(c))
-    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
deleted file mode 100644
index c4ad698ba76..00000000000
--- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-use crate::ty::context::TyCtxt;
-use crate::ty::{DefId, DefIdTree};
-use rustc_span::def_id::CRATE_DEF_ID;
-use smallvec::SmallVec;
-use std::mem;
-
-use DefIdForest::*;
-
-/// Represents a forest of `DefId`s closed under the ancestor relation. That is,
-/// if a `DefId` representing a module is contained in the forest then all
-/// `DefId`s defined in that module or submodules are also implicitly contained
-/// in the forest.
-///
-/// This is used to represent a set of modules in which a type is visibly
-/// uninhabited.
-///
-/// We store the minimal set of `DefId`s required to represent the whole set. If A and B are
-/// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is
-/// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored.
-#[derive(Copy, Clone, HashStable, Debug)]
-pub enum DefIdForest<'a> {
-    Empty,
-    Single(DefId),
-    /// This variant is very rare.
-    /// Invariant: >1 elements
-    Multiple(&'a [DefId]),
-}
-
-/// Tests whether a slice of roots contains a given DefId.
-#[inline]
-fn slice_contains<'tcx>(tcx: TyCtxt<'tcx>, slice: &[DefId], id: DefId) -> bool {
-    slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
-}
-
-impl<'tcx> DefIdForest<'tcx> {
-    /// Creates an empty forest.
-    pub fn empty() -> DefIdForest<'tcx> {
-        DefIdForest::Empty
-    }
-
-    /// Creates a forest consisting of a single tree representing the entire
-    /// crate.
-    #[inline]
-    pub fn full() -> DefIdForest<'tcx> {
-        DefIdForest::from_id(CRATE_DEF_ID.to_def_id())
-    }
-
-    /// Creates a forest containing a `DefId` and all its descendants.
-    pub fn from_id(id: DefId) -> DefIdForest<'tcx> {
-        DefIdForest::Single(id)
-    }
-
-    fn as_slice(&self) -> &[DefId] {
-        match self {
-            Empty => &[],
-            Single(id) => std::slice::from_ref(id),
-            Multiple(root_ids) => root_ids,
-        }
-    }
-
-    // Only allocates in the rare `Multiple` case.
-    fn from_vec(tcx: TyCtxt<'tcx>, root_ids: SmallVec<[DefId; 1]>) -> DefIdForest<'tcx> {
-        match &root_ids[..] {
-            [] => Empty,
-            [id] => Single(*id),
-            _ => DefIdForest::Multiple(tcx.arena.alloc_from_iter(root_ids)),
-        }
-    }
-
-    /// Tests whether the forest is empty.
-    pub fn is_empty(&self) -> bool {
-        match self {
-            Empty => true,
-            Single(..) | Multiple(..) => false,
-        }
-    }
-
-    /// Iterate over the set of roots.
-    fn iter(&self) -> impl Iterator<Item = DefId> + '_ {
-        self.as_slice().iter().copied()
-    }
-
-    /// Tests whether the forest contains a given DefId.
-    pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool {
-        slice_contains(tcx, self.as_slice(), id)
-    }
-
-    /// Calculate the intersection of a collection of forests.
-    pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx>
-    where
-        I: IntoIterator<Item = DefIdForest<'tcx>>,
-    {
-        let mut iter = iter.into_iter();
-        let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() {
-            SmallVec::from_slice(first.as_slice())
-        } else {
-            return DefIdForest::full();
-        };
-
-        let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
-        for next_forest in iter {
-            // No need to continue if the intersection is already empty.
-            if ret.is_empty() || next_forest.is_empty() {
-                return DefIdForest::empty();
-            }
-
-            // We keep the elements in `ret` that are also in `next_forest`.
-            next_ret.extend(ret.iter().copied().filter(|&id| next_forest.contains(tcx, id)));
-            // We keep the elements in `next_forest` that are also in `ret`.
-            next_ret.extend(next_forest.iter().filter(|&id| slice_contains(tcx, &ret, id)));
-
-            mem::swap(&mut next_ret, &mut ret);
-            next_ret.clear();
-        }
-        DefIdForest::from_vec(tcx, ret)
-    }
-
-    /// Calculate the union of a collection of forests.
-    pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx>
-    where
-        I: IntoIterator<Item = DefIdForest<'tcx>>,
-    {
-        let mut ret: SmallVec<[_; 1]> = SmallVec::new();
-        let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
-        for next_forest in iter {
-            // Union with the empty set is a no-op.
-            if next_forest.is_empty() {
-                continue;
-            }
-
-            // We add everything in `ret` that is not in `next_forest`.
-            next_ret.extend(ret.iter().copied().filter(|&id| !next_forest.contains(tcx, id)));
-            // We add everything in `next_forest` that we haven't added yet.
-            for id in next_forest.iter() {
-                if !slice_contains(tcx, &next_ret, id) {
-                    next_ret.push(id);
-                }
-            }
-
-            mem::swap(&mut next_ret, &mut ret);
-            next_ret.clear();
-        }
-        DefIdForest::from_vec(tcx, ret)
-    }
-}
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
new file mode 100644
index 00000000000..b7aa455727d
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
@@ -0,0 +1,204 @@
+use crate::ty::context::TyCtxt;
+use crate::ty::{self, DefId, DefIdTree, ParamEnv, Ty};
+
+/// Represents whether some type is inhabited in a given context.
+/// Examples of uninhabited types are `!`, `enum Void {}`, or a struct
+/// containing either of those types.
+/// A type's inhabitedness may depend on the `ParamEnv` as well as what types
+/// are visible in the current module.
+#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
+pub enum InhabitedPredicate<'tcx> {
+    /// Inhabited
+    True,
+    /// Uninhabited
+    False,
+    /// Uninhabited when a const value is non-zero. This occurs when there is an
+    /// array of uninhabited items, but the array is inhabited if it is empty.
+    ConstIsZero(ty::Const<'tcx>),
+    /// Uninhabited if within a certain module. This occurs when an uninhabited
+    /// type has restricted visibility.
+    NotInModule(DefId),
+    /// Inhabited if some generic type is inhabited.
+    /// These are replaced by calling [`Self::subst`].
+    GenericType(Ty<'tcx>),
+    /// A AND B
+    And(&'tcx [InhabitedPredicate<'tcx>; 2]),
+    /// A OR B
+    Or(&'tcx [InhabitedPredicate<'tcx>; 2]),
+}
+
+impl<'tcx> InhabitedPredicate<'tcx> {
+    /// Returns true if the corresponding type is inhabited in the given
+    /// `ParamEnv` and module
+    pub fn apply(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, module_def_id: DefId) -> bool {
+        let Ok(result) = self
+            .apply_inner::<!>(tcx, param_env, &|id| Ok(tcx.is_descendant_of(module_def_id, id)));
+        result
+    }
+
+    /// Same as `apply`, but returns `None` if self contains a module predicate
+    pub fn apply_any_module(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
+        self.apply_inner(tcx, param_env, &|_| Err(())).ok()
+    }
+
+    fn apply_inner<E>(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        in_module: &impl Fn(DefId) -> Result<bool, E>,
+    ) -> Result<bool, E> {
+        match self {
+            Self::False => Ok(false),
+            Self::True => Ok(true),
+            Self::ConstIsZero(const_) => match const_.try_eval_usize(tcx, param_env) {
+                None | Some(0) => Ok(true),
+                Some(1..) => Ok(false),
+            },
+            Self::NotInModule(id) => in_module(id).map(|in_mod| !in_mod),
+            Self::GenericType(_) => Ok(true),
+            Self::And([a, b]) => try_and(a, b, |x| x.apply_inner(tcx, param_env, in_module)),
+            Self::Or([a, b]) => try_or(a, b, |x| x.apply_inner(tcx, param_env, in_module)),
+        }
+    }
+
+    pub fn and(self, tcx: TyCtxt<'tcx>, other: Self) -> Self {
+        self.reduce_and(tcx, other).unwrap_or_else(|| Self::And(tcx.arena.alloc([self, other])))
+    }
+
+    pub fn or(self, tcx: TyCtxt<'tcx>, other: Self) -> Self {
+        self.reduce_or(tcx, other).unwrap_or_else(|| Self::Or(tcx.arena.alloc([self, other])))
+    }
+
+    pub fn all(tcx: TyCtxt<'tcx>, iter: impl IntoIterator<Item = Self>) -> Self {
+        let mut result = Self::True;
+        for pred in iter {
+            if matches!(pred, Self::False) {
+                return Self::False;
+            }
+            result = result.and(tcx, pred);
+        }
+        result
+    }
+
+    pub fn any(tcx: TyCtxt<'tcx>, iter: impl IntoIterator<Item = Self>) -> Self {
+        let mut result = Self::False;
+        for pred in iter {
+            if matches!(pred, Self::True) {
+                return Self::True;
+            }
+            result = result.or(tcx, pred);
+        }
+        result
+    }
+
+    fn reduce_and(self, tcx: TyCtxt<'tcx>, other: Self) -> Option<Self> {
+        match (self, other) {
+            (Self::True, a) | (a, Self::True) => Some(a),
+            (Self::False, _) | (_, Self::False) => Some(Self::False),
+            (Self::ConstIsZero(a), Self::ConstIsZero(b)) if a == b => Some(Self::ConstIsZero(a)),
+            (Self::NotInModule(a), Self::NotInModule(b)) if a == b => Some(Self::NotInModule(a)),
+            (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(a, b) => {
+                Some(Self::NotInModule(b))
+            }
+            (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(b, a) => {
+                Some(Self::NotInModule(a))
+            }
+            (Self::GenericType(a), Self::GenericType(b)) if a == b => Some(Self::GenericType(a)),
+            (Self::And(&[a, b]), c) | (c, Self::And(&[a, b])) => {
+                if let Some(ac) = a.reduce_and(tcx, c) {
+                    Some(ac.and(tcx, b))
+                } else if let Some(bc) = b.reduce_and(tcx, c) {
+                    Some(Self::And(tcx.arena.alloc([a, bc])))
+                } else {
+                    None
+                }
+            }
+            _ => None,
+        }
+    }
+
+    fn reduce_or(self, tcx: TyCtxt<'tcx>, other: Self) -> Option<Self> {
+        match (self, other) {
+            (Self::True, _) | (_, Self::True) => Some(Self::True),
+            (Self::False, a) | (a, Self::False) => Some(a),
+            (Self::ConstIsZero(a), Self::ConstIsZero(b)) if a == b => Some(Self::ConstIsZero(a)),
+            (Self::NotInModule(a), Self::NotInModule(b)) if a == b => Some(Self::NotInModule(a)),
+            (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(a, b) => {
+                Some(Self::NotInModule(a))
+            }
+            (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(b, a) => {
+                Some(Self::NotInModule(b))
+            }
+            (Self::GenericType(a), Self::GenericType(b)) if a == b => Some(Self::GenericType(a)),
+            (Self::Or(&[a, b]), c) | (c, Self::Or(&[a, b])) => {
+                if let Some(ac) = a.reduce_or(tcx, c) {
+                    Some(ac.or(tcx, b))
+                } else if let Some(bc) = b.reduce_or(tcx, c) {
+                    Some(Self::Or(tcx.arena.alloc([a, bc])))
+                } else {
+                    None
+                }
+            }
+            _ => None,
+        }
+    }
+
+    /// Replaces generic types with its corresponding predicate
+    pub fn subst(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Self {
+        self.subst_opt(tcx, substs).unwrap_or(self)
+    }
+
+    fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option<Self> {
+        match self {
+            Self::ConstIsZero(c) => {
+                let c = ty::EarlyBinder(c).subst(tcx, substs);
+                let pred = match c.kind().try_to_machine_usize(tcx) {
+                    Some(0) => Self::True,
+                    Some(1..) => Self::False,
+                    None => Self::ConstIsZero(c),
+                };
+                Some(pred)
+            }
+            Self::GenericType(t) => {
+                Some(ty::EarlyBinder(t).subst(tcx, substs).inhabited_predicate(tcx))
+            }
+            Self::And(&[a, b]) => match a.subst_opt(tcx, substs) {
+                None => b.subst_opt(tcx, substs).map(|b| a.and(tcx, b)),
+                Some(InhabitedPredicate::False) => Some(InhabitedPredicate::False),
+                Some(a) => Some(a.and(tcx, b.subst_opt(tcx, substs).unwrap_or(b))),
+            },
+            Self::Or(&[a, b]) => match a.subst_opt(tcx, substs) {
+                None => b.subst_opt(tcx, substs).map(|b| a.or(tcx, b)),
+                Some(InhabitedPredicate::True) => Some(InhabitedPredicate::True),
+                Some(a) => Some(a.or(tcx, b.subst_opt(tcx, substs).unwrap_or(b))),
+            },
+            _ => None,
+        }
+    }
+}
+
+// this is basically like `f(a)? && f(b)?` but different in the case of
+// `Ok(false) && Err(_) -> Ok(false)`
+fn try_and<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E> {
+    let a = f(a);
+    if matches!(a, Ok(false)) {
+        return Ok(false);
+    }
+    match (a, f(b)) {
+        (_, Ok(false)) | (Ok(false), _) => Ok(false),
+        (Ok(true), Ok(true)) => Ok(true),
+        (Err(e), _) | (_, Err(e)) => Err(e),
+    }
+}
+
+fn try_or<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E> {
+    let a = f(a);
+    if matches!(a, Ok(true)) {
+        return Ok(true);
+    }
+    match (a, f(b)) {
+        (_, Ok(true)) | (Ok(true), _) => Ok(true),
+        (Ok(false), Ok(false)) => Ok(false),
+        (Err(e), _) | (_, Err(e)) => Err(e),
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index aaa66deb2a3..279a728ea39 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -1,57 +1,60 @@
-pub use self::def_id_forest::DefIdForest;
+//! This module contains logic for determining whether a type is inhabited or
+//! uninhabited. The [`InhabitedPredicate`] type captures the minimum
+//! information needed to determine whether a type is inhabited given a
+//! `ParamEnv` and module ID.
+//!
+//! # Example
+//! ```rust
+//! enum Void {}
+//! mod a {
+//!     pub mod b {
+//!         pub struct SecretlyUninhabited {
+//!             _priv: !,
+//!         }
+//!     }
+//! }
+//!
+//! mod c {
+//!     pub struct AlsoSecretlyUninhabited {
+//!         _priv: Void,
+//!     }
+//!     mod d {
+//!     }
+//! }
+//!
+//! struct Foo {
+//!     x: a::b::SecretlyUninhabited,
+//!     y: c::AlsoSecretlyUninhabited,
+//! }
+//! ```
+//! In this code, the type `Foo` will only be visibly uninhabited inside the
+//! modules `b`, `c` and `d`. Calling `uninhabited_predicate` on `Foo` will
+//! return `NotInModule(b) AND NotInModule(c)`.
+//!
+//! We need this information for pattern-matching on `Foo` or types that contain
+//! `Foo`.
+//!
+//! # Example
+//! ```rust
+//! let foo_result: Result<T, Foo> = ... ;
+//! let Ok(t) = foo_result;
+//! ```
+//! This code should only compile in modules where the uninhabitedness of `Foo`
+//! is visible.
 
-use crate::ty;
 use crate::ty::context::TyCtxt;
-use crate::ty::{AdtDef, FieldDef, Ty, VariantDef};
-use crate::ty::{AdtKind, Visibility};
-use crate::ty::{DefId, SubstsRef};
+use crate::ty::{self, DefId, Ty, VariantDef, Visibility};
 
 use rustc_type_ir::sty::TyKind::*;
 
-mod def_id_forest;
+pub mod inhabited_predicate;
 
-// The methods in this module calculate `DefIdForest`s of modules in which an
-// `AdtDef`/`VariantDef`/`FieldDef` is visibly uninhabited.
-//
-// # Example
-// ```rust
-// enum Void {}
-// mod a {
-//     pub mod b {
-//         pub struct SecretlyUninhabited {
-//             _priv: !,
-//         }
-//     }
-// }
-//
-// mod c {
-//     pub struct AlsoSecretlyUninhabited {
-//         _priv: Void,
-//     }
-//     mod d {
-//     }
-// }
-//
-// struct Foo {
-//     x: a::b::SecretlyUninhabited,
-//     y: c::AlsoSecretlyUninhabited,
-// }
-// ```
-// In this code, the type `Foo` will only be visibly uninhabited inside the
-// modules `b`, `c` and `d`. Calling `uninhabited_from` on `Foo` or its `AdtDef` will
-// return the forest of modules {`b`, `c`->`d`} (represented in a `DefIdForest` by the
-// set {`b`, `c`}).
-//
-// We need this information for pattern-matching on `Foo` or types that contain
-// `Foo`.
-//
-// # Example
-// ```rust
-// let foo_result: Result<T, Foo> = ... ;
-// let Ok(t) = foo_result;
-// ```
-// This code should only compile in modules where the uninhabitedness of `Foo` is
-// visible.
+pub use inhabited_predicate::InhabitedPredicate;
+
+pub(crate) fn provide(providers: &mut ty::query::Providers) {
+    *providers =
+        ty::query::Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers };
+}
 
 impl<'tcx> TyCtxt<'tcx> {
     /// Checks whether a type is visibly uninhabited from a particular module.
@@ -100,131 +103,92 @@ impl<'tcx> TyCtxt<'tcx> {
         ty: Ty<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> bool {
-        // To check whether this type is uninhabited at all (not just from the
-        // given node), you could check whether the forest is empty.
-        // ```
-        // forest.is_empty()
-        // ```
-        ty.uninhabited_from(self, param_env).contains(self, module)
+        !ty.inhabited_predicate(self).apply(self, param_env, module)
     }
 }
 
-impl<'tcx> AdtDef<'tcx> {
-    /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited.
-    fn uninhabited_from(
-        self,
-        tcx: TyCtxt<'tcx>,
-        substs: SubstsRef<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> DefIdForest<'tcx> {
-        // Non-exhaustive ADTs from other crates are always considered inhabited.
-        if self.is_variant_list_non_exhaustive() && !self.did().is_local() {
-            DefIdForest::empty()
-        } else {
-            DefIdForest::intersection(
-                tcx,
-                self.variants()
-                    .iter()
-                    .map(|v| v.uninhabited_from(tcx, substs, self.adt_kind(), param_env)),
-            )
+/// Returns an `InhabitedPredicate` that is generic over type parameters and
+/// requires calling [`InhabitedPredicate::subst`]
+fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> {
+    if let Some(def_id) = def_id.as_local() {
+        if matches!(tcx.representability(def_id), ty::Representability::Infinite) {
+            return InhabitedPredicate::True;
         }
     }
+    let adt = tcx.adt_def(def_id);
+    InhabitedPredicate::any(
+        tcx,
+        adt.variants().iter().map(|variant| variant.inhabited_predicate(tcx, adt)),
+    )
 }
 
 impl<'tcx> VariantDef {
     /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited.
-    pub fn uninhabited_from(
+    pub fn inhabited_predicate(
         &self,
         tcx: TyCtxt<'tcx>,
-        substs: SubstsRef<'tcx>,
-        adt_kind: AdtKind,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> DefIdForest<'tcx> {
-        let is_enum = match adt_kind {
-            // For now, `union`s are never considered uninhabited.
-            // The precise semantics of inhabitedness with respect to unions is currently undecided.
-            AdtKind::Union => return DefIdForest::empty(),
-            AdtKind::Enum => true,
-            AdtKind::Struct => false,
-        };
-        // Non-exhaustive variants from other crates are always considered inhabited.
+        adt: ty::AdtDef<'_>,
+    ) -> InhabitedPredicate<'tcx> {
+        debug_assert!(!adt.is_union());
         if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
-            DefIdForest::empty()
-        } else {
-            DefIdForest::union(
-                tcx,
-                self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum, param_env)),
-            )
+            // Non-exhaustive variants from other crates are always considered inhabited.
+            return InhabitedPredicate::True;
         }
-    }
-}
-
-impl<'tcx> FieldDef {
-    /// Calculates the forest of `DefId`s from which this field is visibly uninhabited.
-    fn uninhabited_from(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        substs: SubstsRef<'tcx>,
-        is_enum: bool,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> DefIdForest<'tcx> {
-        let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env);
-        if is_enum {
-            data_uninhabitedness()
-        } else {
-            match self.vis {
-                Visibility::Restricted(from) => {
-                    let forest = DefIdForest::from_id(from);
-                    let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness()));
-                    DefIdForest::intersection(tcx, iter)
+        InhabitedPredicate::all(
+            tcx,
+            self.fields.iter().map(|field| {
+                let pred = tcx.type_of(field.did).inhabited_predicate(tcx);
+                if adt.is_enum() {
+                    return pred;
                 }
-                Visibility::Public => data_uninhabitedness(),
-            }
-        }
+                match field.vis {
+                    Visibility::Public => pred,
+                    Visibility::Restricted(from) => {
+                        pred.or(tcx, InhabitedPredicate::NotInModule(from))
+                    }
+                }
+            }),
+        )
     }
 }
 
 impl<'tcx> Ty<'tcx> {
-    /// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
-    fn uninhabited_from(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> DefIdForest<'tcx> {
-        tcx.type_uninhabited_from(param_env.and(self))
+    pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> {
+        match self.kind() {
+            // For now, union`s are always considered inhabited
+            Adt(adt, _) if adt.is_union() => InhabitedPredicate::True,
+            // Non-exhaustive ADTs from other crates are always considered inhabited
+            Adt(adt, _) if adt.is_variant_list_non_exhaustive() && !adt.did().is_local() => {
+                InhabitedPredicate::True
+            }
+            Never => InhabitedPredicate::False,
+            Param(_) | Projection(_) => InhabitedPredicate::GenericType(self),
+            Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
+            // use a query for more complex cases
+            Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
+            // references and other types are inhabited
+            _ => InhabitedPredicate::True,
+        }
     }
 }
 
-// Query provider for `type_uninhabited_from`.
-pub(crate) fn type_uninhabited_from<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
-) -> DefIdForest<'tcx> {
-    let ty = key.value;
-    let param_env = key.param_env;
+/// N.B. this query should only be called through `Ty::inhabited_predicate`
+fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedPredicate<'tcx> {
     match *ty.kind() {
-        Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
+        Adt(adt, substs) => tcx.inhabited_predicate_adt(adt.did()).subst(tcx, substs),
 
-        Never => DefIdForest::full(),
-
-        Tuple(ref tys) => {
-            DefIdForest::union(tcx, tys.iter().map(|ty| ty.uninhabited_from(tcx, param_env)))
+        Tuple(tys) => {
+            InhabitedPredicate::all(tcx, tys.iter().map(|ty| ty.inhabited_predicate(tcx)))
         }
 
-        Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
-            Some(0) | None => DefIdForest::empty(),
-            // If the array is definitely non-empty, it's uninhabited if
-            // the type of its elements is uninhabited.
-            Some(1..) => ty.uninhabited_from(tcx, param_env),
+        // If we can evaluate the array length before having a `ParamEnv`, then
+        // we can simplify the predicate. This is an optimization.
+        Array(ty, len) => match len.kind().try_to_machine_usize(tcx) {
+            Some(0) => InhabitedPredicate::True,
+            Some(1..) => ty.inhabited_predicate(tcx),
+            None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)),
         },
 
-        // References to uninitialised memory are valid for any type, including
-        // uninhabited types, in unsafe code, so we treat all references as
-        // inhabited.
-        // The precise semantics of inhabitedness with respect to references is currently
-        // undecided.
-        Ref(..) => DefIdForest::empty(),
-
-        _ => DefIdForest::empty(),
+        _ => bug!("unexpected TyKind, use `Ty::inhabited_predicate`"),
     }
 }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 6045c1acdd0..3312f44c67b 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -196,16 +196,16 @@ impl<'a> IntoDiagnostic<'a, !> for LayoutError<'a> {
         match self {
             LayoutError::Unknown(ty) => {
                 diag.set_arg("ty", ty);
-                diag.set_primary_message(rustc_errors::fluent::middle::unknown_layout);
+                diag.set_primary_message(rustc_errors::fluent::middle_unknown_layout);
             }
             LayoutError::SizeOverflow(ty) => {
                 diag.set_arg("ty", ty);
-                diag.set_primary_message(rustc_errors::fluent::middle::values_too_big);
+                diag.set_primary_message(rustc_errors::fluent::middle_values_too_big);
             }
             LayoutError::NormalizationFailure(ty, e) => {
                 diag.set_arg("ty", ty);
                 diag.set_arg("failure_ty", e.get_type_for_failure());
-                diag.set_primary_message(rustc_errors::fluent::middle::cannot_be_normalized);
+                diag.set_primary_message(rustc_errors::fluent::middle_cannot_be_normalized);
             }
         }
         diag
@@ -830,7 +830,7 @@ where
                 } else {
                     match mt {
                         hir::Mutability::Not => {
-                            if ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env()) {
+                            if ty.is_freeze(tcx, cx.param_env()) {
                                 PointerKind::Frozen
                             } else {
                                 PointerKind::SharedMutable
@@ -841,7 +841,7 @@ where
                             // noalias, as another pointer to the structure can be obtained, that
                             // is not based-on the original reference. We consider all !Unpin
                             // types to be potentially self-referential here.
-                            if ty.is_unpin(tcx.at(DUMMY_SP), cx.param_env()) {
+                            if ty.is_unpin(tcx, cx.param_env()) {
                                 PointerKind::UniqueBorrowed
                             } else {
                                 PointerKind::UniqueBorrowedPinned
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 12d24d6751e..27090c62d21 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -17,7 +17,7 @@ pub use self::IntVarValue::*;
 pub use self::Variance::*;
 use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
 use crate::metadata::ModChild;
-use crate::middle::privacy::AccessLevels;
+use crate::middle::privacy::EffectiveVisibilities;
 use crate::mir::{Body, GeneratorLayout};
 use crate::traits::{self, Reveal};
 use crate::ty;
@@ -26,6 +26,7 @@ use crate::ty::util::Discr;
 pub use adt::*;
 pub use assoc::*;
 pub use generics::*;
+use hir::OpaqueTyOrigin;
 use rustc_ast as ast;
 use rustc_ast::node_id::NodeMap;
 use rustc_attr as attr;
@@ -37,11 +38,13 @@ use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, LifetimeRes, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap};
+use rustc_hir::definitions::Definitions;
 use rustc_hir::Node;
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::{Decodable, Encodable};
+use rustc_session::cstore::CrateStoreDyn;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{ExpnId, Span};
@@ -77,7 +80,7 @@ pub use self::consts::{
 };
 pub use self::context::{
     tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
-    CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData,
+    CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GeneratorDiagnosticData,
     GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
     UserTypeAnnotationIndex,
 };
@@ -131,6 +134,7 @@ mod generics;
 mod impls_ty;
 mod instance;
 mod list;
+mod opaque_types;
 mod parameterized;
 mod rvalue_scopes;
 mod structural_impls;
@@ -140,8 +144,15 @@ mod sty;
 
 pub type RegisteredTools = FxHashSet<Ident>;
 
-#[derive(Debug)]
 pub struct ResolverOutputs {
+    pub definitions: Definitions,
+    pub global_ctxt: ResolverGlobalCtxt,
+    pub ast_lowering: ResolverAstLowering,
+}
+
+#[derive(Debug)]
+pub struct ResolverGlobalCtxt {
+    pub cstore: Box<CrateStoreDyn>,
     pub visibilities: FxHashMap<LocalDefId, Visibility>,
     /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error.
     pub has_pub_restricted: bool,
@@ -149,7 +160,7 @@ pub struct ResolverOutputs {
     pub expn_that_defined: FxHashMap<LocalDefId, ExpnId>,
     /// Reference span for definitions.
     pub source_span: IndexVec<LocalDefId, Span>,
-    pub access_levels: AccessLevels,
+    pub effective_visibilities: EffectiveVisibilities,
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
     pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
@@ -681,7 +692,7 @@ pub enum PredicateKind<'tcx> {
     Coerce(CoercePredicate<'tcx>),
 
     /// Constant initializer must evaluate successfully.
-    ConstEvaluatable(ty::UnevaluatedConst<'tcx>),
+    ConstEvaluatable(ty::Const<'tcx>),
 
     /// Constants must be equal. The first component is the const that is expected.
     ConstEquate(Const<'tcx>, Const<'tcx>),
@@ -1300,6 +1311,106 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
             sub: sub_diag,
         });
     }
+
+    #[instrument(level = "debug", skip(tcx), ret)]
+    pub fn remap_generic_params_to_declaration_params(
+        self,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
+        tcx: TyCtxt<'tcx>,
+        // typeck errors have subpar spans for opaque types, so delay error reporting until borrowck.
+        ignore_errors: bool,
+        origin: OpaqueTyOrigin,
+    ) -> Self {
+        let OpaqueTypeKey { def_id, substs } = opaque_type_key;
+
+        // Use substs to build up a reverse map from regions to their
+        // identity mappings. This is necessary because of `impl
+        // Trait` lifetimes are computed by replacing existing
+        // 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());
+        debug!(?id_substs);
+
+        let map = substs.iter().zip(id_substs);
+
+        let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = match origin {
+            // HACK: The HIR lowering for async fn does not generate
+            // any `+ Captures<'x>` bounds for the `impl Future<...>`, so all async fns with lifetimes
+            // would now fail to compile. We should probably just make hir lowering fill this in properly.
+            OpaqueTyOrigin::AsyncFn(_) => map.collect(),
+            OpaqueTyOrigin::FnReturn(_) | OpaqueTyOrigin::TyAlias => {
+                // Opaque types may only use regions that are bound. So for
+                // ```rust
+                // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
+                // ```
+                // we may not use `'c` in the hidden type.
+                struct OpaqueTypeLifetimeCollector<'tcx> {
+                    lifetimes: FxHashSet<ty::Region<'tcx>>,
+                }
+
+                impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> {
+                    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+                        self.lifetimes.insert(r);
+                        r.super_visit_with(self)
+                    }
+                }
+
+                let mut collector = OpaqueTypeLifetimeCollector { lifetimes: Default::default() };
+
+                for pred in tcx.bound_explicit_item_bounds(def_id.to_def_id()).transpose_iter() {
+                    let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
+
+                    trace!(pred=?pred.kind());
+
+                    // We only ignore opaque type substs if the opaque type is the outermost type.
+                    // The opaque type may be nested within itself via recursion in e.g.
+                    // type Foo<'a> = impl PartialEq<Foo<'a>>;
+                    // which thus mentions `'a` and should thus accept hidden types that borrow 'a
+                    // instead of requiring an additional `+ 'a`.
+                    match pred.kind().skip_binder() {
+                        ty::PredicateKind::Trait(TraitPredicate {
+                            trait_ref: ty::TraitRef { def_id: _, substs },
+                            constness: _,
+                            polarity: _,
+                        }) => {
+                            trace!(?substs);
+                            for subst in &substs[1..] {
+                                subst.visit_with(&mut collector);
+                            }
+                        }
+                        ty::PredicateKind::Projection(ty::ProjectionPredicate {
+                            projection_ty: ty::ProjectionTy { substs, item_def_id: _ },
+                            term,
+                        }) => {
+                            for subst in &substs[1..] {
+                                subst.visit_with(&mut collector);
+                            }
+                            term.visit_with(&mut collector);
+                        }
+                        _ => {
+                            pred.visit_with(&mut collector);
+                        }
+                    }
+                }
+                let lifetimes = collector.lifetimes;
+                trace!(?lifetimes);
+                map.filter(|(_, v)| {
+                    let ty::GenericArgKind::Lifetime(lt) = v.unpack() else {
+                        return true;
+                    };
+                    lifetimes.contains(&lt)
+                })
+                .collect()
+            }
+        };
+        debug!("map = {:#?}", map);
+
+        // Convert the type from the function into a type valid outside
+        // the function, by replacing invalid regions with 'static,
+        // after producing an error for each of them.
+        self.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span, ignore_errors))
+    }
 }
 
 /// The "placeholder index" fully defines a placeholder region, type, or const. Placeholders are
@@ -2493,7 +2604,9 @@ impl<'tcx> TyCtxt<'tcx> {
             && if self.features().collapse_debuginfo {
                 span.in_macro_expansion_with_collapse_debuginfo()
             } else {
-                span.from_expansion()
+                // Inlined spans should not be collapsed as that leads to all of the
+                // inlined code being attributed to the inline callsite.
+                span.from_expansion() && !span.is_inlined()
             }
     }
 
@@ -2592,6 +2705,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
     closure::provide(providers);
     context::provide(providers);
     erase_regions::provide(providers);
+    inhabitedness::provide(providers);
     util::provide(providers);
     print::provide(providers);
     super::util::bug::provide(providers);
@@ -2599,7 +2713,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
         trait_impls_of: trait_def::trait_impls_of_provider,
         incoherent_impls: trait_def::incoherent_impls_provider,
-        type_uninhabited_from: inhabitedness::type_uninhabited_from,
         const_param_default: consts::const_param_default,
         vtable_allocation: vtable::vtable_allocation_provider,
         ..*providers
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index fe303e21b65..ee13920d52e 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -214,15 +214,6 @@ impl<'tcx> TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
     fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
         self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
     }
-
-    #[inline]
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
-        // FIXME: This *probably* needs canonicalization too!
-        let arg = self.param_env.and(c);
-        self.tcx
-            .try_normalize_mir_const_after_erasing_regions(arg)
-            .unwrap_or_else(|_| bug!("failed to normalize {:?}", c))
-    }
 }
 
 struct TryNormalizeAfterErasingRegionsFolder<'tcx> {
@@ -267,16 +258,4 @@ impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'t
             Err(_) => Err(NormalizationError::Const(c)),
         }
     }
-
-    fn try_fold_mir_const(
-        &mut self,
-        c: mir::ConstantKind<'tcx>,
-    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
-        // FIXME: This *probably* needs canonicalization too!
-        let arg = self.param_env.and(c);
-        match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) {
-            Ok(c) => Ok(c),
-            Err(_) => Err(NormalizationError::ConstantKind(c)),
-        }
-    }
 }
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
new file mode 100644
index 00000000000..b05c6310929
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -0,0 +1,218 @@
+use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_span::Span;
+
+/// Converts generic params of a TypeFoldable from one
+/// item's generics to another. Usually from a function's generics
+/// list to the opaque type's own generics.
+pub(super) struct ReverseMapper<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
+    /// see call sites to fold_kind_no_missing_regions_error
+    /// for an explanation of this field.
+    do_not_error: bool,
+
+    /// We do not want to emit any errors in typeck because
+    /// the spans in typeck are subpar at the moment.
+    /// Borrowck will do the same work again (this time with
+    /// lifetime information) and thus report better errors.
+    ignore_errors: bool,
+
+    /// Span of function being checked.
+    span: Span,
+}
+
+impl<'tcx> ReverseMapper<'tcx> {
+    pub(super) fn new(
+        tcx: TyCtxt<'tcx>,
+        map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
+        span: Span,
+        ignore_errors: bool,
+    ) -> Self {
+        Self { tcx, map, do_not_error: false, ignore_errors, span }
+    }
+
+    fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
+        assert!(!self.do_not_error);
+        self.do_not_error = true;
+        let kind = kind.fold_with(self);
+        self.do_not_error = false;
+        kind
+    }
+
+    fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
+        assert!(!self.do_not_error);
+        kind.fold_with(self)
+    }
+}
+
+impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        match *r {
+            // Ignore bound regions and `'static` regions that appear in the
+            // type, we only need to remap regions that reference lifetimes
+            // from the function declaration.
+            // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
+            ty::ReLateBound(..) | ty::ReStatic => return r,
+
+            // If regions have been erased (by writeback), don't try to unerase
+            // them.
+            ty::ReErased => return r,
+
+            // The regions that we expect from borrow checking.
+            ty::ReEarlyBound(_) | ty::ReFree(_) => {}
+
+            ty::RePlaceholder(_) | ty::ReVar(_) => {
+                // All of the regions in the type should either have been
+                // erased by writeback, or mapped back to named regions by
+                // borrow checking.
+                bug!("unexpected region kind in opaque type: {:?}", r);
+            }
+        }
+
+        match self.map.get(&r.into()).map(|k| k.unpack()) {
+            Some(GenericArgKind::Lifetime(r1)) => r1,
+            Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
+            None if self.do_not_error => self.tcx.lifetimes.re_static,
+            None => {
+                self.tcx
+                    .sess
+                    .struct_span_err(self.span, "non-defining opaque type use in defining scope")
+                    .span_label(
+                        self.span,
+                        format!(
+                            "lifetime `{}` is part of concrete type but not used in \
+                                 parameter list of the `impl Trait` type alias",
+                            r
+                        ),
+                    )
+                    .emit();
+
+                self.tcx().lifetimes.re_static
+            }
+        }
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        match *ty.kind() {
+            ty::Closure(def_id, substs) => {
+                // I am a horrible monster and I pray for death. When
+                // we encounter a closure here, it is always a closure
+                // from within the function that we are currently
+                // type-checking -- one that is now being encapsulated
+                // in an opaque type. Ideally, we would
+                // go through the types/lifetimes that it references
+                // and treat them just like we would any other type,
+                // which means we would error out if we find any
+                // reference to a type/region that is not in the
+                // "reverse map".
+                //
+                // **However,** in the case of closures, there is a
+                // somewhat subtle (read: hacky) consideration. The
+                // problem is that our closure types currently include
+                // all the lifetime parameters declared on the
+                // enclosing function, even if they are unused by the
+                // closure itself. We can't readily filter them out,
+                // so here we replace those values with `'empty`. This
+                // can't really make a difference to the rest of the
+                // compiler; those regions are ignored for the
+                // outlives relation, and hence don't affect trait
+                // selection or auto traits, and they are erased
+                // during codegen.
+
+                let generics = self.tcx.generics_of(def_id);
+                let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
+                    if index < generics.parent_count {
+                        // Accommodate missing regions in the parent kinds...
+                        self.fold_kind_no_missing_regions_error(kind)
+                    } else {
+                        // ...but not elsewhere.
+                        self.fold_kind_normally(kind)
+                    }
+                }));
+
+                self.tcx.mk_closure(def_id, substs)
+            }
+
+            ty::Generator(def_id, substs, movability) => {
+                let generics = self.tcx.generics_of(def_id);
+                let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
+                    if index < generics.parent_count {
+                        // Accommodate missing regions in the parent kinds...
+                        self.fold_kind_no_missing_regions_error(kind)
+                    } else {
+                        // ...but not elsewhere.
+                        self.fold_kind_normally(kind)
+                    }
+                }));
+
+                self.tcx.mk_generator(def_id, substs, movability)
+            }
+
+            ty::Param(param) => {
+                // Look it up in the substitution list.
+                match self.map.get(&ty.into()).map(|k| k.unpack()) {
+                    // Found it in the substitution list; replace with the parameter from the
+                    // opaque type.
+                    Some(GenericArgKind::Type(t1)) => t1,
+                    Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
+                    None => {
+                        debug!(?param, ?self.map);
+                        if !self.ignore_errors {
+                            self.tcx
+                                .sess
+                                .struct_span_err(
+                                    self.span,
+                                    &format!(
+                                        "type parameter `{}` is part of concrete type but not \
+                                          used in parameter list for the `impl Trait` type alias",
+                                        ty
+                                    ),
+                                )
+                                .emit();
+                        }
+
+                        self.tcx().ty_error()
+                    }
+                }
+            }
+
+            _ => ty.super_fold_with(self),
+        }
+    }
+
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        trace!("checking const {:?}", ct);
+        // Find a const parameter
+        match ct.kind() {
+            ty::ConstKind::Param(..) => {
+                // Look it up in the substitution list.
+                match self.map.get(&ct.into()).map(|k| k.unpack()) {
+                    // Found it in the substitution list, replace with the parameter from the
+                    // opaque type.
+                    Some(GenericArgKind::Const(c1)) => c1,
+                    Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
+                    None => {
+                        if !self.ignore_errors {
+                            self.tcx.sess.emit_err(ty::ConstNotUsedTraitAlias {
+                                ct: ct.to_string(),
+                                span: self.span,
+                            });
+                        }
+
+                        self.tcx().const_error(ct.ty())
+                    }
+                }
+            }
+
+            _ => ct,
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index f289f2265a2..e1e705a922f 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -61,6 +61,7 @@ trivially_parameterized_over_tcx! {
     crate::middle::resolve_lifetime::ObjectLifetimeDefault,
     crate::mir::ConstQualifs,
     ty::AssocItemContainer,
+    ty::DeducedParamAttrs,
     ty::Generics,
     ty::ImplPolarity,
     ty::ReprOptions,
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index e0a8d58f8a7..44b9548db89 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -3,7 +3,7 @@ use crate::ty::{self, DefIdTree, Ty, TyCtxt};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sso::SsoHashSet;
-use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 
 // `pretty` is a separate module only for organization.
@@ -325,3 +325,12 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> {
         cx.print_const(*self)
     }
 }
+
+// This is only used by query descriptions
+pub fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
+    if def_id.is_top_level_module() {
+        "top-level module".to_string()
+    } else {
+        format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 66354196b4e..fab85c39d25 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -16,6 +16,7 @@ use rustc_session::cstore::{ExternCrate, ExternCrateSource};
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
+use smallvec::SmallVec;
 
 use std::cell::Cell;
 use std::char;
@@ -595,7 +596,7 @@ pub trait PrettyPrinter<'tcx>:
             }
             ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
             ty::Infer(infer_ty) => {
-                let verbose = self.tcx().sess.verbose();
+                let verbose = self.should_print_verbose();
                 if let ty::TyVar(ty_vid) = infer_ty {
                     if let Some(name) = self.ty_infer_name(ty_vid) {
                         p!(write("{}", name))
@@ -637,7 +638,7 @@ pub trait PrettyPrinter<'tcx>:
                 p!(print_def_path(def_id, &[]));
             }
             ty::Projection(ref data) => {
-                if !(self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get()))
+                if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get()))
                     && self.tcx().def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder
                 {
                     return self.pretty_print_opaque_impl_type(data.item_def_id, data.substs);
@@ -653,7 +654,7 @@ pub trait PrettyPrinter<'tcx>:
                 // only affect certain debug messages (e.g. messages printed
                 // from `rustc_middle::ty` during the computation of `tcx.predicates_of`),
                 // and should have no effect on any compiler output.
-                if self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get()) {
+                if self.should_print_verbose() || NO_QUERIES.with(|q| q.get()) {
                     p!(write("Opaque({:?}, {:?})", def_id, substs));
                     return Ok(self);
                 }
@@ -684,7 +685,7 @@ pub trait PrettyPrinter<'tcx>:
                     hir::Movability::Static => p!("static "),
                 }
 
-                if !self.tcx().sess.verbose() {
+                if !self.should_print_verbose() {
                     p!("generator");
                     // FIXME(eddyb) should use `def_span`.
                     if let Some(did) = did.as_local() {
@@ -720,7 +721,7 @@ pub trait PrettyPrinter<'tcx>:
             }
             ty::Closure(did, substs) => {
                 p!(write("["));
-                if !self.tcx().sess.verbose() {
+                if !self.should_print_verbose() {
                     p!(write("closure"));
                     // FIXME(eddyb) should use `def_span`.
                     if let Some(did) = did.as_local() {
@@ -758,7 +759,7 @@ pub trait PrettyPrinter<'tcx>:
             }
             ty::Array(ty, sz) => {
                 p!("[", print(ty), "; ");
-                if self.tcx().sess.verbose() {
+                if self.should_print_verbose() {
                     p!(write("{:?}", sz));
                 } else if let ty::ConstKind::Unevaluated(..) = sz.kind() {
                     // Do not try to evaluate unevaluated constants. If we are const evaluating an
@@ -794,9 +795,9 @@ pub trait PrettyPrinter<'tcx>:
         let mut traits = FxIndexMap::default();
         let mut fn_traits = FxIndexMap::default();
         let mut is_sized = false;
+        let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new();
 
-        for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
-            let predicate = predicate.subst(tcx, substs);
+        for (predicate, _) in bounds.subst_iter_copied(tcx, substs) {
             let bound_predicate = predicate.kind();
 
             match bound_predicate.skip_binder() {
@@ -825,6 +826,9 @@ pub trait PrettyPrinter<'tcx>:
                         &mut fn_traits,
                     );
                 }
+                ty::PredicateKind::TypeOutlives(outlives) => {
+                    lifetimes.push(outlives.1);
+                }
                 _ => {}
             }
         }
@@ -978,6 +982,11 @@ pub trait PrettyPrinter<'tcx>:
             write!(self, "Sized")?;
         }
 
+        for re in lifetimes {
+            write!(self, " + ")?;
+            self = self.print_region(re)?;
+        }
+
         Ok(self)
     }
 
@@ -1064,7 +1073,7 @@ pub trait PrettyPrinter<'tcx>:
 
                 // Special-case `Fn(...) -> ...` and re-sugar it.
                 let fn_trait_kind = cx.tcx().fn_trait_kind_from_lang_item(principal.def_id);
-                if !cx.tcx().sess.verbose() && fn_trait_kind.is_some() {
+                if !cx.should_print_verbose() && fn_trait_kind.is_some() {
                     if let ty::Tuple(tys) = principal.substs.type_at(0).kind() {
                         let mut projections = predicates.projection_bounds();
                         if let (Some(proj), None) = (projections.next(), projections.next()) {
@@ -1128,7 +1137,7 @@ pub trait PrettyPrinter<'tcx>:
         //
         // To avoid causing instabilities in compiletest
         // output, sort the auto-traits alphabetically.
-        auto_traits.sort_by_cached_key(|did| self.tcx().def_path_str(*did));
+        auto_traits.sort_by_cached_key(|did| with_no_trimmed_paths!(self.tcx().def_path_str(*did)));
 
         for def_id in auto_traits {
             if !first {
@@ -1172,7 +1181,7 @@ pub trait PrettyPrinter<'tcx>:
     ) -> Result<Self::Const, Self::Error> {
         define_scoped_cx!(self);
 
-        if self.tcx().sess.verbose() {
+        if self.should_print_verbose() {
             p!(write("Const({:?}: {:?})", ct.kind(), ct.ty()));
             return Ok(self);
         }
@@ -1407,7 +1416,7 @@ pub trait PrettyPrinter<'tcx>:
     ) -> Result<Self::Const, Self::Error> {
         define_scoped_cx!(self);
 
-        if self.tcx().sess.verbose() {
+        if self.should_print_verbose() {
             p!(write("ValTree({:?}: ", valtree), print(ty), ")");
             return Ok(self);
         }
@@ -1551,6 +1560,10 @@ pub trait PrettyPrinter<'tcx>:
             Ok(cx)
         })
     }
+
+    fn should_print_verbose(&self) -> bool {
+        self.tcx().sess.verbose()
+    }
 }
 
 // HACK(eddyb) boxed to avoid moving around a large struct by-value.
@@ -1826,7 +1839,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
             }
         }
 
-        let verbose = self.tcx.sess.verbose();
+        let verbose = self.should_print_verbose();
         disambiguated_data.fmt_maybe_verbose(&mut self, verbose)?;
 
         self.empty_path = false;
@@ -1927,7 +1940,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
             return true;
         }
 
-        if self.tcx.sess.verbose() {
+        if self.should_print_verbose() {
             return true;
         }
 
@@ -1999,7 +2012,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
             return Ok(self);
         }
 
-        if self.tcx.sess.verbose() {
+        if self.should_print_verbose() {
             p!(write("{:?}", region));
             return Ok(self);
         }
@@ -2205,7 +2218,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
         // aren't named. Eventually, we might just want this as the default, but
         // this is not *quite* right and changes the ordering of some output
         // anyways.
-        let (new_value, map) = if self.tcx().sess.verbose() {
+        let (new_value, map) = if self.should_print_verbose() {
             let regions: Vec<_> = value
                 .bound_vars()
                 .into_iter()
@@ -2702,8 +2715,8 @@ define_print_and_forward_display! {
                 print_value_path(closure_def_id, &[]),
                 write("` implements the trait `{}`", kind))
             }
-            ty::PredicateKind::ConstEvaluatable(uv) => {
-                p!("the constant `", print_value_path(uv.def.did, uv.substs), "` can be evaluated")
+            ty::PredicateKind::ConstEvaluatable(ct) => {
+                p!("the constant `", print(ct), "` can be evaluated")
             }
             ty::PredicateKind::ConstEquate(c1, c2) => {
                 p!("the constant `", print(c1), "` equals `", print(c2), "`")
@@ -2727,7 +2740,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
     // Iterate all local crate items no matter where they are defined.
     let hir = tcx.hir();
     for id in hir.items() {
-        if matches!(tcx.def_kind(id.def_id), DefKind::Use) {
+        if matches!(tcx.def_kind(id.owner_id), DefKind::Use) {
             continue;
         }
 
@@ -2736,7 +2749,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
             continue;
         }
 
-        let def_id = item.def_id.to_def_id();
+        let def_id = item.owner_id.to_def_id();
         let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
         collect_fn(&item.ident, ns, def_id);
     }
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index ce1b69935f2..ec90590ada2 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -5,7 +5,7 @@ use crate::metadata::ModChild;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
 use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use crate::middle::lib_features::LibFeatures;
-use crate::middle::privacy::AccessLevels;
+use crate::middle::privacy::EffectiveVisibilities;
 use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes};
 use crate::middle::stability::{self, DeprecationEntry};
 use crate::mir;
@@ -40,6 +40,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::unord::UnordSet;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
@@ -52,7 +53,6 @@ use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolMangli
 use rustc_session::cstore::{CrateDepKind, CrateSource};
 use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
 use rustc_session::lint::LintExpectationId;
-use rustc_session::utils::NativeLibKind;
 use rustc_session::Limits;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index cdb618e030a..b25b4bd4fe3 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -574,8 +574,8 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
 /// it.
 pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
     relation: &mut R,
-    a: ty::Const<'tcx>,
-    b: ty::Const<'tcx>,
+    mut a: ty::Const<'tcx>,
+    mut b: ty::Const<'tcx>,
 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
     debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
     let tcx = relation.tcx();
@@ -596,6 +596,17 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
         );
     }
 
+    // HACK(const_generics): We still need to eagerly evaluate consts when
+    // relating them because during `normalize_param_env_or_error`,
+    // we may relate an evaluated constant in a obligation against
+    // an unnormalized (i.e. unevaluated) const in the param-env.
+    // FIXME(generic_const_exprs): Once we always lazily unify unevaluated constants
+    // these `eval` calls can be removed.
+    if !relation.tcx().features().generic_const_exprs {
+        a = a.eval(tcx, relation.param_env());
+        b = b.eval(tcx, relation.param_env());
+    }
+
     // Currently, the values that can be unified are primitive types,
     // and those that derive both `PartialEq` and `Eq`, corresponding
     // to structural-match types.
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 1164cf3e01a..23cd93d6af4 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -166,8 +166,8 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
             ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                 write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
             }
-            ty::PredicateKind::ConstEvaluatable(uv) => {
-                write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs)
+            ty::PredicateKind::ConstEvaluatable(ct) => {
+                write!(f, "ConstEvaluatable({ct:?})")
             }
             ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
             ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
@@ -240,7 +240,6 @@ TrivialTypeTraversalAndLiftImpls! {
     Field,
     interpret::Scalar,
     rustc_target::abi::Size,
-    ty::DelaySpanBugEmitted,
     rustc_type_ir::DebruijnIndex,
     ty::BoundVar,
     ty::Placeholder<ty::BoundVar>,
@@ -832,27 +831,6 @@ impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::UnevaluatedConst<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        folder.try_fold_ty_unevaluated(self)
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for ty::UnevaluatedConst<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        visitor.visit_ty_unevaluated(*self)
-    }
-}
-
-impl<'tcx> TypeSuperFoldable<'tcx> for ty::UnevaluatedConst<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        Ok(ty::UnevaluatedConst { def: self.def, substs: self.substs.try_fold_with(folder)? })
-    }
-}
-
 impl<'tcx> TypeSuperVisitable<'tcx> for ty::UnevaluatedConst<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.substs.visit_with(visitor)
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 64636963313..cf420bafeb1 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2205,7 +2205,10 @@ impl<'tcx> Ty<'tcx> {
             // These aren't even `Clone`
             ty::Str | ty::Slice(..) | ty::Foreign(..) | ty::Dynamic(..) => false,
 
-            ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
+            ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_))
+            | ty::Int(..)
+            | ty::Uint(..)
+            | ty::Float(..) => true,
 
             // The voldemort ZSTs are fine.
             ty::FnDef(..) => true,
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 36eb2ab5157..0660e9b79a7 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -1,12 +1,12 @@
 // Type substitutions.
 
-use crate::mir;
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
 use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
 use crate::ty::visit::{TypeVisitable, TypeVisitor};
 use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::intern::{Interned, WithStableHash};
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
@@ -189,6 +189,14 @@ impl<'tcx> GenericArg<'tcx> {
             _ => bug!("expected a const, but found another kind"),
         }
     }
+
+    pub fn is_non_region_infer(self) -> bool {
+        match self.unpack() {
+            GenericArgKind::Lifetime(_) => false,
+            GenericArgKind::Type(ty) => ty.is_ty_infer(),
+            GenericArgKind::Const(ct) => ct.is_ct_infer(),
+        }
+    }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
@@ -551,6 +559,28 @@ impl<T, U> EarlyBinder<(T, U)> {
     }
 }
 
+impl<'tcx, 's, T: IntoIterator<Item = I>, I: TypeFoldable<'tcx>> EarlyBinder<T> {
+    pub fn subst_iter(
+        self,
+        tcx: TyCtxt<'tcx>,
+        substs: &'s [GenericArg<'tcx>],
+    ) -> impl Iterator<Item = I> + Captures<'s> + Captures<'tcx> {
+        self.0.into_iter().map(move |t| EarlyBinder(t).subst(tcx, substs))
+    }
+}
+
+impl<'tcx, 's, 'a, T: IntoIterator<Item = &'a I>, I: Copy + TypeFoldable<'tcx> + 'a>
+    EarlyBinder<T>
+{
+    pub fn subst_iter_copied(
+        self,
+        tcx: TyCtxt<'tcx>,
+        substs: &'s [GenericArg<'tcx>],
+    ) -> impl Iterator<Item = I> + Captures<'s> + Captures<'tcx> + Captures<'a> {
+        self.0.into_iter().map(move |t| EarlyBinder(*t).subst(tcx, substs))
+    }
+}
+
 pub struct EarlyBinderIter<T> {
     t: T,
 }
@@ -606,9 +636,21 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         #[cold]
         #[inline(never)]
-        fn region_param_out_of_range(data: ty::EarlyBoundRegion) -> ! {
+        fn region_param_out_of_range(data: ty::EarlyBoundRegion, substs: &[GenericArg<'_>]) -> ! {
             bug!(
-                "Region parameter out of range when substituting in region {} (index={})",
+                "Region parameter out of range when substituting in region {} (index={}, substs = {:?})",
+                data.name,
+                data.index,
+                substs,
+            )
+        }
+
+        #[cold]
+        #[inline(never)]
+        fn region_param_invalid(data: ty::EarlyBoundRegion, other: GenericArgKind<'_>) -> ! {
+            bug!(
+                "Unexpected parameter {:?} when substituting in region {} (index={})",
+                other,
                 data.name,
                 data.index
             )
@@ -624,7 +666,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
                 let rk = self.substs.get(data.index as usize).map(|k| k.unpack());
                 match rk {
                     Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
-                    _ => region_param_out_of_range(data),
+                    Some(other) => region_param_invalid(data, other),
+                    None => region_param_out_of_range(data, self.substs),
                 }
             }
             _ => r,
@@ -649,11 +692,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
             c.super_fold_with(self)
         }
     }
-
-    #[inline]
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
-        c.super_fold_with(self)
-    }
 }
 
 impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 713f9067a85..f72e236eda1 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -2,7 +2,6 @@
 
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::ty::layout::IntegerExt;
-use crate::ty::query::TyCtxtAt;
 use crate::ty::{
     self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
     TypeVisitable,
@@ -821,12 +820,8 @@ impl<'tcx> Ty<'tcx> {
     /// does copies even when the type actually doesn't satisfy the
     /// full requirements for the `Copy` trait (cc #29149) -- this
     /// winds up being reported as an error during NLL borrow check.
-    pub fn is_copy_modulo_regions(
-        self,
-        tcx_at: TyCtxtAt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> bool {
-        self.is_trivially_pure_clone_copy() || tcx_at.is_copy_raw(param_env.and(self))
+    pub fn is_copy_modulo_regions(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+        self.is_trivially_pure_clone_copy() || tcx.is_copy_raw(param_env.and(self))
     }
 
     /// Checks whether values of this type `T` have a size known at
@@ -835,8 +830,8 @@ impl<'tcx> Ty<'tcx> {
     /// over-approximation in generic contexts, where one can have
     /// strange rules like `<T as Foo<'static>>::Bar: Sized` that
     /// actually carry lifetime requirements.
-    pub fn is_sized(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
-        self.is_trivially_sized(tcx_at.tcx) || tcx_at.is_sized_raw(param_env.and(self))
+    pub fn is_sized(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+        self.is_trivially_sized(tcx) || tcx.is_sized_raw(param_env.and(self))
     }
 
     /// Checks whether values of this type `T` implement the `Freeze`
@@ -846,8 +841,8 @@ impl<'tcx> Ty<'tcx> {
     /// optimization as well as the rules around static values. Note
     /// that the `Freeze` trait is not exposed to end users and is
     /// effectively an implementation detail.
-    pub fn is_freeze(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
-        self.is_trivially_freeze() || tcx_at.is_freeze_raw(param_env.and(self))
+    pub fn is_freeze(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+        self.is_trivially_freeze() || tcx.is_freeze_raw(param_env.and(self))
     }
 
     /// Fast path helper for testing if a type is `Freeze`.
@@ -886,8 +881,8 @@ impl<'tcx> Ty<'tcx> {
     }
 
     /// Checks whether values of this type `T` implement the `Unpin` trait.
-    pub fn is_unpin(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
-        self.is_trivially_unpin() || tcx_at.is_unpin_raw(param_env.and(self))
+    pub fn is_unpin(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+        self.is_trivially_unpin() || tcx.is_unpin_raw(param_env.and(self))
     }
 
     /// Fast path helper for testing if a type is `Unpin`.
@@ -958,7 +953,7 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
-    /// Checks if `ty` has has a significant drop.
+    /// Checks if `ty` has a significant drop.
     ///
     /// Note that this method can return false even if `ty` has a destructor
     /// attached; even if that is the case then the adt has been marked with
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 44efb93a53b..f0e9f990a81 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -10,8 +10,7 @@
 //!
 //! There are three groups of traits involved in each traversal.
 //! - `TypeVisitable`. This is implemented once for many types, including:
-//!   - Types of interest, for which the the methods delegate to the
-//!     visitor.
+//!   - Types of interest, for which the methods delegate to the visitor.
 //!   - All other types, including generic containers like `Vec` and `Option`.
 //!     It defines a "skeleton" of how they should be visited.
 //! - `TypeSuperVisitable`. This is implemented only for each type of interest,
@@ -39,7 +38,6 @@
 //!     - ty.super_visit_with(visitor)
 //! - u.visit_with(visitor)
 //! ```
-use crate::mir;
 use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
 use rustc_errors::ErrorGuaranteed;
 
@@ -97,11 +95,11 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
     fn references_error(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_ERROR)
     }
-    fn error_reported(&self) -> Option<ErrorGuaranteed> {
+    fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
         if self.references_error() {
-            Some(ErrorGuaranteed::unchecked_claim_error_was_emitted())
+            Err(ErrorGuaranteed::unchecked_claim_error_was_emitted())
         } else {
-            None
+            Ok(())
         }
     }
     fn has_non_region_param(&self) -> bool {
@@ -199,27 +197,9 @@ pub trait TypeVisitor<'tcx>: Sized {
         c.super_visit_with(self)
     }
 
-    fn visit_ty_unevaluated(
-        &mut self,
-        uv: ty::UnevaluatedConst<'tcx>,
-    ) -> ControlFlow<Self::BreakTy> {
-        uv.super_visit_with(self)
-    }
-
-    fn visit_mir_unevaluated(
-        &mut self,
-        uv: mir::UnevaluatedConst<'tcx>,
-    ) -> ControlFlow<Self::BreakTy> {
-        uv.super_visit_with(self)
-    }
-
     fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
         p.super_visit_with(self)
     }
-
-    fn visit_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> {
-        c.super_visit_with(self)
-    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -607,34 +587,6 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
 
     #[inline]
     #[instrument(level = "trace", ret)]
-    fn visit_ty_unevaluated(
-        &mut self,
-        uv: ty::UnevaluatedConst<'tcx>,
-    ) -> ControlFlow<Self::BreakTy> {
-        let flags = FlagComputation::for_unevaluated_const(uv);
-        trace!(r.flags=?flags);
-        if flags.intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-
-    fn visit_mir_unevaluated(
-        &mut self,
-        uv: mir::UnevaluatedConst<'tcx>,
-    ) -> ControlFlow<Self::BreakTy> {
-        let flags = FlagComputation::for_unevaluated_const(uv.shrink());
-        trace!(r.flags=?flags);
-        if flags.intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-
-    #[inline]
-    #[instrument(level = "trace", ret)]
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
         debug!(
             "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index a3e11bbf056..91db9698c41 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -112,6 +112,22 @@ impl<'tcx> Ty<'tcx> {
     }
 }
 
+impl<'tcx> ty::Const<'tcx> {
+    /// Iterator that walks `self` and any types reachable from
+    /// `self`, in depth-first order. Note that just walks the types
+    /// that appear in `self`, it does not descend into the fields of
+    /// structs or variants. For example:
+    ///
+    /// ```text
+    /// isize => { isize }
+    /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+    /// [isize] => { [isize], isize }
+    /// ```
+    pub fn walk(self) -> TypeWalker<'tcx> {
+        TypeWalker::new(self.into())
+    }
+}
+
 /// We push `GenericArg`s on the stack in reverse order so as to
 /// maintain a pre-order traversal. As of the time of this
 /// writing, the fact that the traversal is pre-order is not
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 e707c373f0d..c8610af7038 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -153,12 +153,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         if tcx.features().unsized_fn_params {
             let ty = expr.ty;
-            let span = expr.span;
             let param_env = this.param_env;
 
-            if !ty.is_sized(tcx.at(span), param_env) {
+            if !ty.is_sized(tcx, param_env) {
                 // !sized means !copy, so this is an unsized move
-                assert!(!ty.is_copy_modulo_regions(tcx.at(span), param_env));
+                assert!(!ty.is_copy_modulo_regions(tcx, param_env));
 
                 // As described above, detect the case where we are passing a value of unsized
                 // type, and that value is coming from the deref of a box.
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 35a00da8d38..5c82fb1ddc0 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -2,6 +2,7 @@
 
 use rustc_index::vec::Idx;
 use rustc_middle::ty::util::IntTypeExt;
+use rustc_target::abi::{Abi, Primitive};
 
 use crate::build::expr::as_place::PlaceBase;
 use crate::build::expr::category::{Category, RvalueFunc};
@@ -197,16 +198,64 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // create all the steps directly in MIR with operations all backends need to support anyway.
                 let (source, ty) = if let ty::Adt(adt_def, ..) = source.ty.kind() && adt_def.is_enum() {
                     let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx);
-                    let place = unpack!(block = this.as_place(block, source));
+                    let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not));
+                    let layout = this.tcx.layout_of(this.param_env.and(source.ty));
                     let discr = this.temp(discr_ty, source.span);
                     this.cfg.push_assign(
                         block,
                         source_info,
                         discr,
-                        Rvalue::Discriminant(place),
+                        Rvalue::Discriminant(temp.into()),
                     );
+                    let (op,ty) = (Operand::Move(discr), discr_ty);
+
+                    if let Abi::Scalar(scalar) = layout.unwrap().abi{
+                        if let Primitive::Int(_, signed) = scalar.primitive() {
+                            let range = scalar.valid_range(&this.tcx);
+                            // FIXME: Handle wraparound cases too.
+                            if range.end >= range.start {
+                                let mut assumer = |range: u128, bin_op: BinOp| {
+                                    // We will be overwriting this val if our scalar is signed value
+                                    // because sign extension on unsigned types might cause unintended things
+                                    let mut range_val =
+                                        ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(discr_ty));
+                                    let bool_ty = this.tcx.types.bool;
+                                    if signed {
+                                        let scalar_size_extend = scalar.size(&this.tcx).sign_extend(range);
+                                        let discr_layout = this.tcx.layout_of(this.param_env.and(discr_ty));
+                                        let truncated_val = discr_layout.unwrap().size.truncate(scalar_size_extend);
+                                        range_val = ConstantKind::from_bits(
+                                            this.tcx,
+                                            truncated_val,
+                                            ty::ParamEnv::empty().and(discr_ty),
+                                        );
+                                    }
+                                    let lit_op = this.literal_operand(expr.span, range_val);
+                                    let is_bin_op = this.temp(bool_ty, expr_span);
+                                    this.cfg.push_assign(
+                                        block,
+                                        source_info,
+                                        is_bin_op,
+                                        Rvalue::BinaryOp(bin_op, Box::new(((lit_op), (Operand::Copy(discr))))),
+                                    );
+                                    this.cfg.push(
+                                        block,
+                                        Statement {
+                                            source_info,
+                                            kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
+                                                Operand::Copy(is_bin_op),
+                                            ))),
+                                        },
+                                    )
+                                };
+                                assumer(range.end, BinOp::Ge);
+                                assumer(range.start, BinOp::Le);
+                            }
+                        }
+                    }
+
+                    (op,ty)
 
-                    (Operand::Move(discr), discr_ty)
                 } else {
                     let ty = source.ty;
                     let source = unpack!(
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 828f32db361..924d2f555b9 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -264,14 +264,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
                     i == variant_index || {
                         self.tcx.features().exhaustive_patterns
-                            && !v
-                                .uninhabited_from(
-                                    self.tcx,
-                                    substs,
-                                    adt_def.adt_kind(),
-                                    self.param_env,
-                                )
-                                .is_empty()
+                            && v.inhabited_predicate(self.tcx, adt_def)
+                                .subst(self.tcx, substs)
+                                .apply_any_module(self.tcx, self.param_env)
+                                != Some(true)
                     }
                 }) && (adt_def.did().is_local()
                     || !adt_def.is_variant_list_non_exhaustive());
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 5e8ce65daf0..fb1ea9ed300 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -260,7 +260,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     };
                     match borrow_kind {
                         BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
-                            if !ty.is_freeze(self.tcx.at(pat.span), self.param_env) {
+                            if !ty.is_freeze(self.tcx, self.param_env) {
                                 self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
                             }
                         }
@@ -457,9 +457,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 if visitor.found {
                     match borrow_kind {
                         BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique
-                            if !self.thir[arg]
-                                .ty
-                                .is_freeze(self.tcx.at(self.thir[arg].span), self.param_env) =>
+                            if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) =>
                         {
                             self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
                         }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index bcf2ed68172..c7a7c3e3fa8 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -159,6 +159,7 @@ impl<'tcx> Cx<'tcx> {
             Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
                 ExprKind::AddressOf { mutability, arg: self.thir.exprs.push(expr) }
             }
+            Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) },
         };
 
         Expr { temp_lifetime, ty: adjustment.target, span, kind }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index ec709a1db51..93a3dd8962a 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -79,7 +79,10 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
         intravisit::walk_local(self, loc);
         let els = loc.els;
         if let Some(init) = loc.init && els.is_some() {
-            self.check_let(&loc.pat, init, loc.span);
+            // Build a span without the else { ... } as we don't want to underline
+            // the entire else block in the IDE setting.
+            let span = loc.span.with_hi(init.span.hi());
+            self.check_let(&loc.pat, init, span);
         }
 
         let (msg, sp) = match loc.source {
@@ -370,8 +373,12 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
 
             // Check if the let source is while, for there is no alternative place to put a prefix,
             // and we shouldn't lint.
+            // For let guards inside a match, prefixes might use bindings of the match pattern,
+            // so can't always be moved out.
+            // FIXME: Add checking whether the bindings are actually used in the prefix,
+            // and lint if they are not.
             let let_source = let_source_parent(self.tcx, top, None);
-            if !matches!(let_source, LetSource::WhileLet) {
+            if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
                 // Emit the lint
                 let prefix = &chain_refutabilities[..until];
                 lint_affix(prefix, "leading", "outside of the construct");
@@ -503,7 +510,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
                                 _ => "aren't",
                             },
                         ),
-                        " else { todo!() }".to_string(),
+                        " else { todo!() }",
                         Applicability::HasPlaceholders,
                     );
                 }
@@ -626,11 +633,6 @@ fn irrefutable_let_patterns(
     count: usize,
     span: Span,
 ) {
-    let span = match source {
-        LetSource::LetElse(span) => span,
-        _ => span,
-    };
-
     macro_rules! emit_diag {
         (
             $lint:expr,
@@ -676,7 +678,7 @@ fn irrefutable_let_patterns(
                 "removing the guard and adding a `let` inside the match arm"
             );
         }
-        LetSource::LetElse(..) => {
+        LetSource::LetElse => {
             emit_diag!(
                 lint,
                 "`let...else`",
@@ -1000,8 +1002,8 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>(
 }
 
 /// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
-fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId, span: Span) -> bool {
-    !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env)
+fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId) -> bool {
+    !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx, cx.param_env)
 }
 
 /// Check that there are no borrow or move conflicts in `binding @ subpat` patterns.
@@ -1027,7 +1029,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
 
     // Get the binding move, extract the mutability if by-ref.
     let mut_outer = match typeck_results.extract_binding_mode(sess, pat.hir_id, pat.span) {
-        Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id, pat.span) => {
+        Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id) => {
             // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
             let mut conflicts_ref = Vec::new();
             sub.each_binding(|_, hir_id, span, _| {
@@ -1066,7 +1068,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
                 (Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push((span, name)), // 2x `ref mut`.
                 _ => conflicts_mut_ref.push((span, name)), // `ref` + `ref mut` in either direction.
             },
-            Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id, span) => {
+            Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => {
                 conflicts_move.push((span, name)) // `ref mut?` + by-move conflict.
             }
             Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine.
@@ -1123,7 +1125,7 @@ pub enum LetSource {
     GenericLet,
     IfLet,
     IfLetGuard,
-    LetElse(Span),
+    LetElse,
     WhileLet,
 }
 
@@ -1151,10 +1153,14 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L
 
     let parent_parent = hir.get_parent_node(parent);
     let parent_parent_node = hir.get(parent_parent);
-    if let hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) =
-        parent_parent_node
-    {
-        return LetSource::LetElse(*span);
+    match parent_parent_node {
+        hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), .. }) => {
+            return LetSource::LetElse;
+        }
+        hir::Node::Arm(hir::Arm { guard: Some(hir::Guard::If(_)), .. }) => {
+            return LetSource::IfLetGuard;
+        }
+        _ => {}
     }
 
     let parent_parent_parent = hir.get_parent_node(parent_parent);
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 cf8ae776be9..ad12e011621 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
@@ -506,7 +506,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 // convert the dereferenced constant to a pattern that is the sub-pattern of the
                 // deref pattern.
                 _ => {
-                    if !pointee_ty.is_sized(tcx.at(span), param_env) {
+                    if !pointee_ty.is_sized(tcx, param_env) {
                         // `tcx.deref_mir_constant()` below will ICE with an unsized type
                         // (except slices, which are handled in a separate arm above).
                         let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
@@ -534,7 +534,7 @@ impl<'tcx> ConstToPat<'tcx> {
             ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => {
                 PatKind::Constant { value: cv }
             }
-            ty::RawPtr(pointee) if pointee.ty.is_sized(tcx.at(span), param_env) => {
+            ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => {
                 PatKind::Constant { value: cv }
             }
             // FIXME: these can have very surprising behaviour where optimization levels or other
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 91ecfccdb5f..595abc8f668 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -988,10 +988,12 @@ impl<'tcx> SplitWildcard<'tcx> {
                     .filter(|(_, v)| {
                         // If `exhaustive_patterns` is enabled, we exclude variants known to be
                         // uninhabited.
-                        let is_uninhabited = is_exhaustive_pat_feature
-                            && v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
-                                .contains(cx.tcx, cx.module);
-                        !is_uninhabited
+                        !is_exhaustive_pat_feature
+                            || v.inhabited_predicate(cx.tcx, *def).subst(cx.tcx, substs).apply(
+                                cx.tcx,
+                                cx.param_env,
+                                cx.module,
+                            )
                     })
                     .map(|(idx, _)| Variant(idx))
                     .collect();
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 895af80bd7f..2526522a25c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -483,7 +483,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         // Use `Reveal::All` here because patterns are always monomorphic even if their function
         // isn't.
         let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx);
-        let substs = self.typeck_results.node_substs(id);
+        // N.B. There is no guarantee that substs collected in typeck results are fully normalized,
+        // so they need to be normalized in order to pass to `Instance::resolve`, which will ICE
+        // if given unnormalized types.
+        let substs = self
+            .tcx
+            .normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_substs(id));
         let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, substs) {
             Ok(Some(i)) => i,
             Ok(None) => {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index f1279072844..8dc9976eaea 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -885,7 +885,7 @@ fn is_useful<'p, 'tcx>(
             // that has the potential to trigger the `non_exhaustive_omitted_patterns` lint.
             // To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors`
             if is_non_exhaustive_and_wild
-                // We check that the match has a wildcard pattern and that that wildcard is useful,
+                // We check that the match has a wildcard pattern and that wildcard is useful,
                 // meaning there are variants that are covered by the wildcard. Without the check
                 // for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}`
                 && usefulness.is_useful() && matches!(witness_preference, RealArm)
diff --git a/compiler/rustc_mir_dataflow/src/errors.rs b/compiler/rustc_mir_dataflow/src/errors.rs
index 5b1a88cb284..cfacc0ec370 100644
--- a/compiler/rustc_mir_dataflow/src/errors.rs
+++ b/compiler/rustc_mir_dataflow/src/errors.rs
@@ -2,21 +2,21 @@ use rustc_macros::Diagnostic;
 use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::path_must_end_in_filename)]
+#[diag(mir_dataflow_path_must_end_in_filename)]
 pub(crate) struct PathMustEndInFilename {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::unknown_formatter)]
+#[diag(mir_dataflow_unknown_formatter)]
 pub(crate) struct UnknownFormatter {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::duplicate_values_for)]
+#[diag(mir_dataflow_duplicate_values_for)]
 pub(crate) struct DuplicateValuesFor {
     #[primary_span]
     pub span: Span,
@@ -24,7 +24,7 @@ pub(crate) struct DuplicateValuesFor {
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::requires_an_argument)]
+#[diag(mir_dataflow_requires_an_argument)]
 pub(crate) struct RequiresAnArgument {
     #[primary_span]
     pub span: Span,
@@ -32,39 +32,39 @@ pub(crate) struct RequiresAnArgument {
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::stop_after_dataflow_ended_compilation)]
+#[diag(mir_dataflow_stop_after_dataflow_ended_compilation)]
 pub(crate) struct StopAfterDataFlowEndedCompilation;
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::peek_must_be_place_or_ref_place)]
+#[diag(mir_dataflow_peek_must_be_place_or_ref_place)]
 pub(crate) struct PeekMustBePlaceOrRefPlace {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::peek_must_be_not_temporary)]
+#[diag(mir_dataflow_peek_must_be_not_temporary)]
 pub(crate) struct PeekMustBeNotTemporary {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::peek_bit_not_set)]
+#[diag(mir_dataflow_peek_bit_not_set)]
 pub(crate) struct PeekBitNotSet {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::peek_argument_not_a_local)]
+#[diag(mir_dataflow_peek_argument_not_a_local)]
 pub(crate) struct PeekArgumentNotALocal {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::peek_argument_untracked)]
+#[diag(mir_dataflow_peek_argument_untracked)]
 pub(crate) struct PeekArgumentUntracked {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 4730be1244b..959fcf8d89e 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -101,12 +101,10 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
             | StatementKind::Retag { .. }
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {
                 // safe (at least as emitted during MIR construction)
             }
-
-            // Move to above list once mir construction uses it.
-            StatementKind::Intrinsic(..) => unreachable!(),
         }
         self.super_statement(statement, location);
     }
@@ -312,7 +310,7 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
                             } else if !place
                                 .ty(self.body, self.tcx)
                                 .ty
-                                .is_freeze(self.tcx.at(self.source_info.span), self.param_env)
+                                .is_freeze(self.tcx, self.param_env)
                             {
                                 UnsafetyViolationDetails::BorrowOfLayoutConstrainedField
                             } else {
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 4a9bd9df327..4e451588845 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -633,7 +633,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
         if !rvalue
             .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx)
-            .is_sized(self.ecx.tcx, self.param_env)
+            .is_sized(*self.ecx.tcx, self.param_env)
         {
             // the interpreter doesn't support unsized locals (only unsized arguments),
             // but rustc does (in a kinda broken way), so we have to skip them here
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 6bddbdb8e6a..479c4e577d4 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -500,7 +500,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
         if !rvalue
             .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx)
-            .is_sized(self.ecx.tcx, self.param_env)
+            .is_sized(*self.ecx.tcx, self.param_env)
         {
             // the interpreter doesn't support unsized locals (only unsized arguments),
             // but rustc does (in a kinda broken way), so we have to skip them here
diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
new file mode 100644
index 00000000000..28b1c5a4809
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
@@ -0,0 +1,248 @@
+//! Deduces supplementary parameter attributes from MIR.
+//!
+//! Deduced parameter attributes are those that can only be soundly determined by examining the
+//! 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.
+
+use rustc_hir::def_id::DefId;
+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};
+use rustc_middle::ty::{self, DeducedParamAttrs, ParamEnv, Ty, TyCtxt};
+use rustc_session::config::OptLevel;
+
+/// A visitor that determines which arguments have been mutated. We can't use the mutability field
+/// on LocalDecl for this because it has no meaning post-optimization.
+struct DeduceReadOnly {
+    /// Each bit is indexed by argument number, starting at zero (so 0 corresponds to local decl
+    /// 1). The bit is true if the argument may have been mutated or false if we know it hasn't
+    /// been up to the point we're at.
+    mutable_args: BitSet<usize>,
+}
+
+impl DeduceReadOnly {
+    /// Returns a new DeduceReadOnly instance.
+    fn new(arg_count: usize) -> Self {
+        Self { mutable_args: BitSet::new_empty(arg_count) }
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
+    fn visit_local(&mut self, local: Local, mut context: PlaceContext, _: Location) {
+        // We're only interested in arguments.
+        if local == RETURN_PLACE || local.index() > self.mutable_args.domain_size() {
+            return;
+        }
+
+        // Replace place contexts that are moves with copies. This is safe in all cases except
+        // function argument position, which we already handled in `visit_terminator()` by using the
+        // ArgumentChecker. See the comment in that method for more details.
+        //
+        // In the future, we might want to move this out into a separate pass, but for now let's
+        // just do it on the fly because that's faster.
+        if matches!(context, PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)) {
+            context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
+        }
+
+        match context {
+            PlaceContext::MutatingUse(..)
+            | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => {
+                // This is a mutation, so mark it as such.
+                self.mutable_args.insert(local.index() - 1);
+            }
+            PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => {
+                // Not mutating, so it's fine.
+            }
+        }
+    }
+
+    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+        // OK, this is subtle. Suppose that we're trying to deduce whether `x` in `f` is read-only
+        // and we have the following:
+        //
+        //     fn f(x: BigStruct) { g(x) }
+        //     fn g(mut y: BigStruct) { y.foo = 1 }
+        //
+        // If, at the generated MIR level, `f` turned into something like:
+        //
+        //      fn f(_1: BigStruct) -> () {
+        //          let mut _0: ();
+        //          bb0: {
+        //              _0 = g(move _1) -> bb1;
+        //          }
+        //          ...
+        //      }
+        //
+        // then it would be incorrect to mark `x` (i.e. `_1`) as `readonly`, because `g`'s write to
+        // its copy of the indirect parameter would actually be a write directly to the pointer that
+        // `f` passes. Note that function arguments are the only situation in which this problem can
+        // arise: every other use of `move` in MIR doesn't actually write to the value it moves
+        // from.
+        //
+        // Anyway, right now this situation doesn't actually arise in practice. Instead, the MIR for
+        // that function looks like this:
+        //
+        //      fn f(_1: BigStruct) -> () {
+        //          let mut _0: ();
+        //          let mut _2: BigStruct;
+        //          bb0: {
+        //              _2 = move _1;
+        //              _0 = g(move _2) -> bb1;
+        //          }
+        //          ...
+        //      }
+        //
+        // Because of that extra move that MIR construction inserts, `x` (i.e. `_1`) can *in
+        // practice* safely be marked `readonly`.
+        //
+        // To handle the possibility that other optimizations (for example, destination propagation)
+        // might someday generate MIR like the first example above, we panic upon seeing an argument
+        // to *our* function that is directly moved into *another* function as an argument. Having
+        // eliminated that problematic case, we can safely treat moves as copies in this analysis.
+        //
+        // In the future, if MIR optimizations cause arguments of a caller to be directly moved into
+        // the argument of a callee, we can just add that argument to `mutated_args` instead of
+        // panicking.
+        //
+        // Note that, because the problematic MIR is never actually generated, we can't add a test
+        // case for this.
+
+        if let TerminatorKind::Call { ref args, .. } = terminator.kind {
+            for arg in args {
+                if let Operand::Move(_) = *arg {
+                    // ArgumentChecker panics if a direct move of an argument from a caller to a
+                    // callee was detected.
+                    //
+                    // If, in the future, MIR optimizations cause arguments to be moved directly
+                    // from callers to callees, change the panic to instead add the argument in
+                    // question to `mutating_uses`.
+                    ArgumentChecker::new(self.mutable_args.domain_size())
+                        .visit_operand(arg, location)
+                }
+            }
+        };
+
+        self.super_terminator(terminator, location);
+    }
+}
+
+/// A visitor that simply panics if a direct move of an argument from a caller to a callee was
+/// detected.
+struct ArgumentChecker {
+    /// The number of arguments to the calling function.
+    arg_count: usize,
+}
+
+impl ArgumentChecker {
+    /// Creates a new ArgumentChecker.
+    fn new(arg_count: usize) -> Self {
+        Self { arg_count }
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for ArgumentChecker {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
+        // Check to make sure that, if this local is an argument, we didn't move directly from it.
+        if matches!(context, PlaceContext::NonMutatingUse(NonMutatingUseContext::Move))
+            && local != RETURN_PLACE
+            && local.index() <= self.arg_count
+        {
+            // If, in the future, MIR optimizations cause arguments to be moved directly from
+            // callers to callees, change this panic to instead add the argument in question to
+            // `mutating_uses`.
+            panic!("Detected a direct move from a caller's argument to a callee's argument!")
+        }
+    }
+}
+
+/// Returns true if values of a given type will never be passed indirectly, regardless of ABI.
+fn type_will_always_be_passed_directly<'tcx>(ty: Ty<'tcx>) -> bool {
+    matches!(
+        ty.kind(),
+        ty::Bool
+            | ty::Char
+            | ty::Float(..)
+            | ty::Int(..)
+            | ty::RawPtr(..)
+            | ty::Ref(..)
+            | ty::Slice(..)
+            | ty::Uint(..)
+    )
+}
+
+/// Returns the deduced parameter attributes for a function.
+///
+/// Deduced parameter attributes are those that can only be soundly determined by examining the
+/// 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] {
+    // 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() {
+        return &[];
+    }
+
+    // If the Freeze language item isn't present, then don't bother.
+    if tcx.lang_items().freeze_trait().is_none() {
+        return &[];
+    }
+
+    // Codegen won't use this information for anything if all the function parameters are passed
+    // directly. Detect that and bail, for compilation speed.
+    let fn_ty = tcx.type_of(def_id);
+    if matches!(fn_ty.kind(), ty::FnDef(..)) {
+        if fn_ty
+            .fn_sig(tcx)
+            .inputs()
+            .skip_binder()
+            .iter()
+            .cloned()
+            .all(type_will_always_be_passed_directly)
+        {
+            return &[];
+        }
+    }
+
+    // Don't deduce any attributes for functions that have no MIR.
+    if !tcx.is_mir_available(def_id) {
+        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);
+    deduce_read_only.visit_body(body);
+
+    // Set the `readonly` attribute for every argument that we concluded is immutable and that
+    // contains no UnsafeCells.
+    //
+    // FIXME: This is overly conservative around generic parameters: `is_freeze()` will always
+    // return false for them. For a description of alternatives that could do a better job here,
+    // see [1].
+    //
+    // [1]: https://github.com/rust-lang/rust/pull/103172#discussion_r999139997
+    let mut deduced_param_attrs = tcx.arena.alloc_from_iter(
+        body.local_decls.iter().skip(1).take(body.arg_count).enumerate().map(
+            |(arg_index, local_decl)| DeducedParamAttrs {
+                read_only: !deduce_read_only.mutable_args.contains(arg_index)
+                    && local_decl.ty.is_freeze(tcx, ParamEnv::reveal_all()),
+            },
+        ),
+    );
+
+    // Trailing parameters past the size of the `deduced_param_attrs` array are assumed to have the
+    // default set of attributes, so we don't have to store them explicitly. Pop them off to save a
+    // few bytes in metadata.
+    while deduced_param_attrs.last() == Some(&DeducedParamAttrs::default()) {
+        let last_index = deduced_param_attrs.len() - 1;
+        deduced_param_attrs = &mut deduced_param_attrs[0..last_index];
+    }
+
+    deduced_param_attrs
+}
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 2230c3399f0..4791be1306c 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -56,6 +56,7 @@ mod const_prop_lint;
 mod coverage;
 mod dead_store_elimination;
 mod deaggregator;
+mod deduce_param_attrs;
 mod deduplicate_blocks;
 mod deref_separator;
 mod dest_prop;
@@ -70,7 +71,6 @@ mod inline;
 mod instcombine;
 mod lower_intrinsics;
 mod lower_slice_len;
-mod marker;
 mod match_branches;
 mod multiple_return_terminators;
 mod normalize_array_len;
@@ -139,6 +139,7 @@ pub fn provide(providers: &mut Providers) {
         promoted_mir_of_const_arg: |tcx, (did, param_did)| {
             promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
         },
+        deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
         ..*providers
     };
 }
@@ -287,7 +288,7 @@ fn mir_const<'tcx>(
 
     let mut body = tcx.mir_built(def).steal();
 
-    rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
+    pass_manager::dump_mir_for_phase_change(tcx, &body);
 
     pm::run_passes(
         tcx,
@@ -301,6 +302,7 @@ fn mir_const<'tcx>(
             &simplify::SimplifyCfg::new("initial"),
             &rustc_peek::SanityCheck, // Just a lint
         ],
+        None,
     );
     tcx.alloc_steal_mir(body)
 }
@@ -340,6 +342,7 @@ fn mir_promoted<'tcx>(
             &simplify::SimplifyCfg::new("promote-consts"),
             &coverage::InstrumentCoverage,
         ],
+        Some(MirPhase::Analysis(AnalysisPhase::Initial)),
     );
 
     let promoted = promote_pass.promoted_fragments.into_inner();
@@ -407,10 +410,8 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
             pm::run_passes(
                 tcx,
                 &mut body,
-                &[
-                    &const_prop::ConstProp,
-                    &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)),
-                ],
+                &[&const_prop::ConstProp],
+                Some(MirPhase::Runtime(RuntimePhase::Optimized)),
             );
         }
     }
@@ -472,6 +473,7 @@ fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>
                 &remove_uninit_drops::RemoveUninitDrops,
                 &simplify::SimplifyCfg::new("remove-false-edges"),
             ],
+            None,
         );
         check_consts::post_drop_elaboration::check_live_drops(tcx, &body); // FIXME: make this a MIR lint
     }
@@ -496,10 +498,9 @@ fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         &cleanup_post_borrowck::CleanupNonCodegenStatements,
         &simplify::SimplifyCfg::new("early-opt"),
         &deref_separator::Derefer,
-        &marker::PhaseChange(MirPhase::Analysis(AnalysisPhase::PostCleanup)),
     ];
 
-    pm::run_passes(tcx, body, passes);
+    pm::run_passes(tcx, body, passes, Some(MirPhase::Analysis(AnalysisPhase::PostCleanup)));
 }
 
 /// Returns the sequence of passes that lowers analysis to runtime MIR.
@@ -524,9 +525,8 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // CTFE support for aggregates.
         &deaggregator::Deaggregator,
         &Lint(const_prop_lint::ConstProp),
-        &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Initial)),
     ];
-    pm::run_passes_no_validate(tcx, body, passes);
+    pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial)));
 }
 
 /// Returns the sequence of passes that do the initial cleanup of runtime MIR.
@@ -535,10 +535,9 @@ fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         &elaborate_box_derefs::ElaborateBoxDerefs,
         &lower_intrinsics::LowerIntrinsics,
         &simplify::SimplifyCfg::new("elaborate-drops"),
-        &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::PostCleanup)),
     ];
 
-    pm::run_passes(tcx, body, passes);
+    pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
 }
 
 fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -589,10 +588,10 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             &deduplicate_blocks::DeduplicateBlocks,
             // Some cleanup necessary at least for LLVM and potentially other codegen backends.
             &add_call_guards::CriticalCallEdges,
-            &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)),
             // Dump the end result for testing and debugging purposes.
             &dump_mir::Marker("PreCodegen"),
         ],
+        Some(MirPhase::Runtime(RuntimePhase::Optimized)),
     );
 }
 
diff --git a/compiler/rustc_mir_transform/src/marker.rs b/compiler/rustc_mir_transform/src/marker.rs
deleted file mode 100644
index 06819fc1d37..00000000000
--- a/compiler/rustc_mir_transform/src/marker.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use std::borrow::Cow;
-
-use crate::MirPass;
-use rustc_middle::mir::{Body, MirPhase};
-use rustc_middle::ty::TyCtxt;
-
-/// Changes the MIR phase without changing the MIR itself.
-pub struct PhaseChange(pub MirPhase);
-
-impl<'tcx> MirPass<'tcx> for PhaseChange {
-    fn phase_change(&self) -> Option<MirPhase> {
-        Some(self.0)
-    }
-
-    fn name(&self) -> Cow<'_, str> {
-        Cow::from(format!("PhaseChange-{:?}", self.0))
-    }
-
-    fn run_pass(&self, _: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
-}
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 67dae71468f..230c6a7cb4b 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -66,10 +66,6 @@ where
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         self.1.run_pass(tcx, body)
     }
-
-    fn phase_change(&self) -> Option<MirPhase> {
-        self.1.phase_change()
-    }
 }
 
 /// Run the sequence of passes without validating the MIR after each pass. The MIR is still
@@ -78,23 +74,28 @@ pub fn run_passes_no_validate<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &mut Body<'tcx>,
     passes: &[&dyn MirPass<'tcx>],
+    phase_change: Option<MirPhase>,
 ) {
-    run_passes_inner(tcx, body, passes, false);
+    run_passes_inner(tcx, body, passes, phase_change, false);
 }
 
-pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>]) {
-    run_passes_inner(tcx, body, passes, true);
+/// The optional `phase_change` is applied after executing all the passes, if present
+pub fn run_passes<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &mut Body<'tcx>,
+    passes: &[&dyn MirPass<'tcx>],
+    phase_change: Option<MirPhase>,
+) {
+    run_passes_inner(tcx, body, passes, phase_change, true);
 }
 
 fn run_passes_inner<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &mut Body<'tcx>,
     passes: &[&dyn MirPass<'tcx>],
+    phase_change: Option<MirPhase>,
     validate_each: bool,
 ) {
-    let start_phase = body.phase;
-    let mut cnt = 0;
-
     let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir;
     let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
     trace!(?overridden_passes);
@@ -102,7 +103,6 @@ fn run_passes_inner<'tcx>(
     for pass in passes {
         let name = pass.name();
 
-        // Gather information about what we should be doing for this pass
         let overridden =
             overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| {
                 trace!(
@@ -112,32 +112,44 @@ fn run_passes_inner<'tcx>(
                 );
                 *polarity
             });
-        let is_enabled = overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess));
-        let new_phase = pass.phase_change();
-        let dump_enabled = (is_enabled && pass.is_mir_dump_enabled()) || new_phase.is_some();
-        let validate = (validate && is_enabled)
-            || new_phase == Some(MirPhase::Runtime(RuntimePhase::Optimized));
+        if !overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess)) {
+            continue;
+        }
+
+        let dump_enabled = pass.is_mir_dump_enabled();
 
         if dump_enabled {
-            dump_mir(tcx, body, start_phase, &name, cnt, false);
-        }
-        if is_enabled {
-            pass.run_pass(tcx, body);
+            dump_mir_for_pass(tcx, body, &name, false);
         }
-        if dump_enabled {
-            dump_mir(tcx, body, start_phase, &name, cnt, true);
-            cnt += 1;
+        if validate {
+            validate_body(tcx, body, format!("before pass {}", name));
         }
-        if let Some(new_phase) = pass.phase_change() {
-            if body.phase >= new_phase {
-                panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase);
-            }
 
-            body.phase = new_phase;
+        pass.run_pass(tcx, body);
+
+        if dump_enabled {
+            dump_mir_for_pass(tcx, body, &name, true);
         }
         if validate {
             validate_body(tcx, body, format!("after pass {}", name));
         }
+
+        body.pass_count += 1;
+    }
+
+    if let Some(new_phase) = phase_change {
+        if body.phase >= new_phase {
+            panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase);
+        }
+
+        body.phase = new_phase;
+
+        dump_mir_for_phase_change(tcx, body);
+        if validate || new_phase == MirPhase::Runtime(RuntimePhase::Optimized) {
+            validate_body(tcx, body, format!("after phase change to {}", new_phase));
+        }
+
+        body.pass_count = 1;
     }
 }
 
@@ -145,22 +157,33 @@ pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: Strin
     validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body);
 }
 
-pub fn dump_mir<'tcx>(
+pub fn dump_mir_for_pass<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    phase: MirPhase,
     pass_name: &str,
-    cnt: usize,
     is_after: bool,
 ) {
-    let phase_index = phase.phase_index();
+    let phase_index = body.phase.phase_index();
 
     mir::dump_mir(
         tcx,
-        Some(&format_args!("{:03}-{:03}", phase_index, cnt)),
+        Some(&format_args!("{:03}-{:03}", phase_index, body.pass_count)),
         pass_name,
         if is_after { &"after" } else { &"before" },
         body,
         |_, _| Ok(()),
     );
 }
+
+pub fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+    let phase_index = body.phase.phase_index();
+
+    mir::dump_mir(
+        tcx,
+        Some(&format_args!("{:03}-000", phase_index)),
+        &format!("{}", body.phase),
+        &"after",
+        body,
+        |_, _| Ok(()),
+    )
+}
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 6ca58ee458c..bf590674144 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -17,7 +17,7 @@ use std::iter;
 
 use crate::util::expand_aggregate;
 use crate::{
-    abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, marker,
+    abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator,
     pass_manager as pm, remove_noop_landing_pads, simplify,
 };
 use rustc_middle::mir::patch::MirPatch;
@@ -97,8 +97,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
             &simplify::SimplifyCfg::new("make_shim"),
             &add_call_guards::CriticalCallEdges,
             &abort_unwinding_calls::AbortUnwindingCalls,
-            &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)),
         ],
+        Some(MirPhase::Runtime(RuntimePhase::Optimized)),
     );
 
     debug!("make_shim({:?}) = {:?}", instance, result);
@@ -312,7 +312,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
     let param_env = tcx.param_env(def_id);
 
     let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
-    let is_copy = self_ty.is_copy_modulo_regions(tcx.at(builder.span), param_env);
+    let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env);
 
     let dest = Place::return_place();
     let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
@@ -845,7 +845,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
         span,
     );
 
-    rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
+    crate::pass_manager::dump_mir_for_phase_change(tcx, &body);
 
     body
 }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 5cd7a7f760f..3cfddd75462 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -201,7 +201,7 @@ use std::iter;
 use std::ops::Range;
 use std::path::PathBuf;
 
-use crate::errors::{LargeAssignmentsLint, RecursionLimit, RequiresLangItem, TypeLengthLimit};
+use crate::errors::{LargeAssignmentsLint, RecursionLimit, TypeLengthLimit};
 
 #[derive(PartialEq)]
 pub enum MonoItemCollectionMode {
@@ -1067,7 +1067,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
     let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
         let param_env = ty::ParamEnv::reveal_all();
         let type_has_metadata = |ty: Ty<'tcx>| -> bool {
-            if ty.is_sized(tcx.at(DUMMY_SP), param_env) {
+            if ty.is_sized(tcx, param_env) {
                 return false;
             }
             let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env);
@@ -1192,7 +1192,7 @@ struct RootCollector<'a, 'tcx> {
 
 impl<'v> RootCollector<'_, 'v> {
     fn process_item(&mut self, id: hir::ItemId) {
-        match self.tcx.def_kind(id.def_id) {
+        match self.tcx.def_kind(id.owner_id) {
             DefKind::Enum | DefKind::Struct | DefKind::Union => {
                 let item = self.tcx.hir().item(id);
                 match item.kind {
@@ -1203,12 +1203,14 @@ impl<'v> RootCollector<'_, 'v> {
                             if self.mode == MonoItemCollectionMode::Eager {
                                 debug!(
                                     "RootCollector: ADT drop-glue for {}",
-                                    self.tcx.def_path_str(item.def_id.to_def_id())
+                                    self.tcx.def_path_str(item.owner_id.to_def_id())
                                 );
 
-                                let ty =
-                                    Instance::new(item.def_id.to_def_id(), InternalSubsts::empty())
-                                        .ty(self.tcx, ty::ParamEnv::reveal_all());
+                                let ty = Instance::new(
+                                    item.owner_id.to_def_id(),
+                                    InternalSubsts::empty(),
+                                )
+                                .ty(self.tcx, ty::ParamEnv::reveal_all());
                                 visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
                             }
                         }
@@ -1219,23 +1221,23 @@ impl<'v> RootCollector<'_, 'v> {
             DefKind::GlobalAsm => {
                 debug!(
                     "RootCollector: ItemKind::GlobalAsm({})",
-                    self.tcx.def_path_str(id.def_id.to_def_id())
+                    self.tcx.def_path_str(id.owner_id.to_def_id())
                 );
                 self.output.push(dummy_spanned(MonoItem::GlobalAsm(id)));
             }
             DefKind::Static(..) => {
                 debug!(
                     "RootCollector: ItemKind::Static({})",
-                    self.tcx.def_path_str(id.def_id.to_def_id())
+                    self.tcx.def_path_str(id.owner_id.to_def_id())
                 );
-                self.output.push(dummy_spanned(MonoItem::Static(id.def_id.to_def_id())));
+                self.output.push(dummy_spanned(MonoItem::Static(id.owner_id.to_def_id())));
             }
             DefKind::Const => {
                 // const items only generate mono items if they are
                 // actually used somewhere. Just declaring them is insufficient.
 
                 // but even just declaring them must collect the items they refer to
-                if let Ok(val) = self.tcx.const_eval_poly(id.def_id.to_def_id()) {
+                if let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id()) {
                     collect_const_value(self.tcx, val, &mut self.output);
                 }
             }
@@ -1246,15 +1248,15 @@ impl<'v> RootCollector<'_, 'v> {
                 }
             }
             DefKind::Fn => {
-                self.push_if_root(id.def_id.def_id);
+                self.push_if_root(id.owner_id.def_id);
             }
             _ => {}
         }
     }
 
     fn process_impl_item(&mut self, id: hir::ImplItemId) {
-        if matches!(self.tcx.def_kind(id.def_id), DefKind::AssocFn) {
-            self.push_if_root(id.def_id.def_id);
+        if matches!(self.tcx.def_kind(id.owner_id), DefKind::AssocFn) {
+            self.push_if_root(id.owner_id.def_id);
         }
     }
 
@@ -1296,14 +1298,7 @@ impl<'v> RootCollector<'_, 'v> {
             return;
         };
 
-        let start_def_id = match self.tcx.lang_items().require(LangItem::Start) {
-            Ok(s) => s,
-            Err(lang_item_err) => {
-                self.tcx
-                    .sess
-                    .emit_fatal(RequiresLangItem { lang_item: lang_item_err.0.name().to_string() });
-            }
-        };
+        let start_def_id = self.tcx.require_lang_item(LangItem::Start, None);
         let main_ret_ty = self.tcx.fn_sig(main_def_id).output();
 
         // Given that `main()` has no arguments,
@@ -1352,13 +1347,13 @@ fn create_mono_items_for_default_impls<'tcx>(
 
             debug!(
                 "create_mono_items_for_default_impls(item={})",
-                tcx.def_path_str(item.def_id.to_def_id())
+                tcx.def_path_str(item.owner_id.to_def_id())
             );
 
-            if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
+            if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
                 let param_env = ty::ParamEnv::reveal_all();
                 let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
-                let overridden_methods = tcx.impl_item_implementor_ids(item.def_id);
+                let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
                 for method in tcx.provided_trait_methods(trait_ref.def_id) {
                     if overridden_methods.contains_key(&method.def_id) {
                         continue;
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index cf6e18c013b..f1ca72de8db 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_macros::{Diagnostic, LintDiagnostic};
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(monomorphize::recursion_limit)]
+#[diag(monomorphize_recursion_limit)]
 pub struct RecursionLimit {
     #[primary_span]
     pub span: Span,
@@ -14,30 +14,24 @@ pub struct RecursionLimit {
     #[note]
     pub def_span: Span,
     pub def_path_str: String,
-    #[note(monomorphize::written_to_path)]
+    #[note(monomorphize_written_to_path)]
     pub was_written: Option<()>,
     pub path: PathBuf,
 }
 
 #[derive(Diagnostic)]
-#[diag(monomorphize::type_length_limit)]
-#[help(monomorphize::consider_type_length_limit)]
+#[diag(monomorphize_type_length_limit)]
+#[help(monomorphize_consider_type_length_limit)]
 pub struct TypeLengthLimit {
     #[primary_span]
     pub span: Span,
     pub shrunk: String,
-    #[note(monomorphize::written_to_path)]
+    #[note(monomorphize_written_to_path)]
     pub was_written: Option<()>,
     pub path: PathBuf,
     pub type_length: usize,
 }
 
-#[derive(Diagnostic)]
-#[diag(monomorphize::requires_lang_item)]
-pub struct RequiresLangItem {
-    pub lang_item: String,
-}
-
 pub struct UnusedGenericParams {
     pub span: Span,
     pub param_spans: Vec<Span>,
@@ -45,12 +39,12 @@ pub struct UnusedGenericParams {
 }
 
 impl IntoDiagnostic<'_> for UnusedGenericParams {
+    #[track_caller]
     fn into_diagnostic(
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag =
-            handler.struct_err(rustc_errors::fluent::monomorphize::unused_generic_params);
+        let mut diag = handler.struct_err(rustc_errors::fluent::monomorphize_unused_generic_params);
         diag.set_span(self.span);
         for (span, name) in self.param_spans.into_iter().zip(self.param_names) {
             // FIXME: I can figure out how to do a label with a fluent string with a fixed message,
@@ -63,7 +57,7 @@ impl IntoDiagnostic<'_> for UnusedGenericParams {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(monomorphize::large_assignments)]
+#[diag(monomorphize_large_assignments)]
 #[note]
 pub struct LargeAssignmentsLint {
     #[label]
@@ -73,11 +67,11 @@ pub struct LargeAssignmentsLint {
 }
 
 #[derive(Diagnostic)]
-#[diag(monomorphize::unknown_partition_strategy)]
+#[diag(monomorphize_unknown_partition_strategy)]
 pub struct UnknownPartitionStrategy;
 
 #[derive(Diagnostic)]
-#[diag(monomorphize::symbol_already_defined)]
+#[diag(monomorphize_symbol_already_defined)]
 pub struct SymbolAlreadyDefined {
     #[primary_span]
     pub span: Option<Span>,
diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs
index 15276569c32..29009c48050 100644
--- a/compiler/rustc_monomorphize/src/partitioning/default.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/default.rs
@@ -319,7 +319,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
             Some(def_id)
         }
         MonoItem::Static(def_id) => Some(def_id),
-        MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.to_def_id()),
+        MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.to_def_id()),
     }
 }
 
@@ -411,9 +411,9 @@ fn mono_item_visibility<'tcx>(
             };
         }
         MonoItem::GlobalAsm(item_id) => {
-            return if tcx.is_reachable_non_generic(item_id.def_id) {
+            return if tcx.is_reachable_non_generic(item_id.owner_id) {
                 *can_be_internalized = false;
-                default_visibility(tcx, item_id.def_id.to_def_id(), false)
+                default_visibility(tcx, item_id.owner_id.to_def_id(), false)
             } else {
                 Visibility::Hidden
             };
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index a93f6a60114..650076c2213 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -276,9 +276,21 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
             ConstantKind::Ty(c) => {
                 c.visit_with(self);
             }
-            ConstantKind::Val(_, ty) | ConstantKind::Unevaluated(_, ty) => {
-                Visitor::visit_ty(self, ty, TyContext::Location(location))
+            ConstantKind::Unevaluated(mir::UnevaluatedConst { def, substs: _, promoted }, ty) => {
+                // Avoid considering `T` unused when constants are of the form:
+                //   `<Self as Foo<T>>::foo::promoted[p]`
+                if let Some(p) = promoted {
+                    if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self {
+                        // If there is a promoted, don't look at the substs - since it will always contain
+                        // the generic parameters, instead, traverse the promoted MIR.
+                        let promoted = self.tcx.promoted_mir(def.did);
+                        self.visit_body(&promoted[p]);
+                    }
+                }
+
+                Visitor::visit_ty(self, ty, TyContext::Location(location));
             }
+            ConstantKind::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)),
         }
     }
 
@@ -310,30 +322,6 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
         }
     }
 
-    fn visit_mir_const(&mut self, constant: ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if !constant.has_non_region_param() {
-            return ControlFlow::CONTINUE;
-        }
-
-        match constant {
-            ConstantKind::Ty(ct) => ct.visit_with(self),
-            ConstantKind::Unevaluated(mir::UnevaluatedConst { def, substs: _, promoted: Some(p) }, _)
-                // Avoid considering `T` unused when constants are of the form:
-                //   `<Self as Foo<T>>::foo::promoted[p]`
-                if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self =>
-            {
-                // If there is a promoted, don't look at the substs - since it will always contain
-                // the generic parameters, instead, traverse the promoted MIR.
-                let promoted = self.tcx.promoted_mir(def.did);
-                self.visit_body(&promoted[p]);
-                ControlFlow::CONTINUE
-            }
-            ConstantKind::Val(..) | ConstantKind::Unevaluated(..) => {
-                constant.super_visit_with(self)
-            }
-        }
-    }
-
     #[instrument(level = "debug", skip(self))]
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !ty.has_non_region_param() {
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 98fee997427..dc204902842 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -9,7 +9,7 @@ use rustc_span::{Span, Symbol};
 use crate::parser::TokenDescription;
 
 #[derive(Diagnostic)]
-#[diag(parser::maybe_report_ambiguous_plus)]
+#[diag(parser_maybe_report_ambiguous_plus)]
 pub(crate) struct AmbiguousPlus {
     pub sum_ty: String,
     #[primary_span]
@@ -18,7 +18,7 @@ pub(crate) struct AmbiguousPlus {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::maybe_recover_from_bad_type_plus, code = "E0178")]
+#[diag(parser_maybe_recover_from_bad_type_plus, code = "E0178")]
 pub(crate) struct BadTypePlus {
     pub ty: String,
     #[primary_span]
@@ -30,7 +30,7 @@ pub(crate) struct BadTypePlus {
 #[derive(Subdiagnostic)]
 pub(crate) enum BadTypePlusSub {
     #[suggestion(
-        parser::add_paren,
+        parser_add_paren,
         code = "{sum_with_parens}",
         applicability = "machine-applicable"
     )]
@@ -39,12 +39,12 @@ pub(crate) enum BadTypePlusSub {
         #[primary_span]
         span: Span,
     },
-    #[label(parser::forgot_paren)]
+    #[label(parser_forgot_paren)]
     ForgotParen {
         #[primary_span]
         span: Span,
     },
-    #[label(parser::expect_path)]
+    #[label(parser_expect_path)]
     ExpectPath {
         #[primary_span]
         span: Span,
@@ -52,7 +52,7 @@ pub(crate) enum BadTypePlusSub {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::maybe_recover_from_bad_qpath_stage_2)]
+#[diag(parser_maybe_recover_from_bad_qpath_stage_2)]
 pub(crate) struct BadQPathStage2 {
     #[primary_span]
     #[suggestion(code = "", applicability = "maybe-incorrect")]
@@ -61,10 +61,10 @@ pub(crate) struct BadQPathStage2 {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::incorrect_semicolon)]
+#[diag(parser_incorrect_semicolon)]
 pub(crate) struct IncorrectSemicolon<'a> {
     #[primary_span]
-    #[suggestion_short(code = "", applicability = "machine-applicable")]
+    #[suggestion(style = "short", code = "", applicability = "machine-applicable")]
     pub span: Span,
     #[help]
     pub opt_help: Option<()>,
@@ -72,26 +72,26 @@ pub(crate) struct IncorrectSemicolon<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::incorrect_use_of_await)]
+#[diag(parser_incorrect_use_of_await)]
 pub(crate) struct IncorrectUseOfAwait {
     #[primary_span]
-    #[suggestion(parser::parentheses_suggestion, code = "", applicability = "machine-applicable")]
+    #[suggestion(parentheses_suggestion, code = "", applicability = "machine-applicable")]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::incorrect_use_of_await)]
+#[diag(parser_incorrect_use_of_await)]
 pub(crate) struct IncorrectAwait {
     #[primary_span]
     pub span: Span,
-    #[suggestion(parser::postfix_suggestion, code = "{expr}.await{question_mark}")]
+    #[suggestion(postfix_suggestion, code = "{expr}.await{question_mark}")]
     pub sugg_span: (Span, Applicability),
     pub expr: String,
     pub question_mark: &'static str,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::in_in_typo)]
+#[diag(parser_in_in_typo)]
 pub(crate) struct InInTypo {
     #[primary_span]
     pub span: Span,
@@ -100,7 +100,7 @@ pub(crate) struct InInTypo {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_variable_declaration)]
+#[diag(parser_invalid_variable_declaration)]
 pub(crate) struct InvalidVariableDeclaration {
     #[primary_span]
     pub span: Span,
@@ -110,26 +110,22 @@ pub(crate) struct InvalidVariableDeclaration {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidVariableDeclarationSub {
-    #[suggestion(
-        parser::switch_mut_let_order,
-        applicability = "maybe-incorrect",
-        code = "let mut"
-    )]
+    #[suggestion(parser_switch_mut_let_order, applicability = "maybe-incorrect", code = "let mut")]
     SwitchMutLetOrder(#[primary_span] Span),
     #[suggestion(
-        parser::missing_let_before_mut,
+        parser_missing_let_before_mut,
         applicability = "machine-applicable",
         code = "let mut"
     )]
     MissingLet(#[primary_span] Span),
-    #[suggestion(parser::use_let_not_auto, applicability = "machine-applicable", code = "let")]
+    #[suggestion(parser_use_let_not_auto, applicability = "machine-applicable", code = "let")]
     UseLetNotAuto(#[primary_span] Span),
-    #[suggestion(parser::use_let_not_var, applicability = "machine-applicable", code = "let")]
+    #[suggestion(parser_use_let_not_var, applicability = "machine-applicable", code = "let")]
     UseLetNotVar(#[primary_span] Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_comparison_operator)]
+#[diag(parser_invalid_comparison_operator)]
 pub(crate) struct InvalidComparisonOperator {
     #[primary_span]
     pub span: Span,
@@ -140,8 +136,9 @@ pub(crate) struct InvalidComparisonOperator {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidComparisonOperatorSub {
-    #[suggestion_short(
-        parser::use_instead,
+    #[suggestion(
+        use_instead,
+        style = "short",
         applicability = "machine-applicable",
         code = "{correct}"
     )]
@@ -151,12 +148,12 @@ pub(crate) enum InvalidComparisonOperatorSub {
         invalid: String,
         correct: String,
     },
-    #[label(parser::spaceship_operator_invalid)]
+    #[label(spaceship_operator_invalid)]
     Spaceship(#[primary_span] Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_logical_operator)]
+#[diag(parser_invalid_logical_operator)]
 #[note]
 pub(crate) struct InvalidLogicalOperator {
     #[primary_span]
@@ -168,14 +165,16 @@ pub(crate) struct InvalidLogicalOperator {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidLogicalOperatorSub {
-    #[suggestion_short(
-        parser::use_amp_amp_for_conjunction,
+    #[suggestion(
+        use_amp_amp_for_conjunction,
+        style = "short",
         applicability = "machine-applicable",
         code = "&&"
     )]
     Conjunction(#[primary_span] Span),
-    #[suggestion_short(
-        parser::use_pipe_pipe_for_disjunction,
+    #[suggestion(
+        use_pipe_pipe_for_disjunction,
+        style = "short",
         applicability = "machine-applicable",
         code = "||"
     )]
@@ -183,15 +182,15 @@ pub(crate) enum InvalidLogicalOperatorSub {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::tilde_is_not_unary_operator)]
+#[diag(parser_tilde_is_not_unary_operator)]
 pub(crate) struct TildeAsUnaryOperator(
     #[primary_span]
-    #[suggestion_short(applicability = "machine-applicable", code = "!")]
+    #[suggestion(style = "short", applicability = "machine-applicable", code = "!")]
     pub Span,
 );
 
 #[derive(Diagnostic)]
-#[diag(parser::unexpected_token_after_not)]
+#[diag(parser_unexpected_token_after_not)]
 pub(crate) struct NotAsNegationOperator {
     #[primary_span]
     pub negated: Span,
@@ -202,22 +201,25 @@ pub(crate) struct NotAsNegationOperator {
 
 #[derive(Subdiagnostic)]
 pub enum NotAsNegationOperatorSub {
-    #[suggestion_short(
-        parser::unexpected_token_after_not_default,
+    #[suggestion(
+        parser_unexpected_token_after_not_default,
+        style = "short",
         applicability = "machine-applicable",
         code = "!"
     )]
     SuggestNotDefault(#[primary_span] Span),
 
-    #[suggestion_short(
-        parser::unexpected_token_after_not_bitwise,
+    #[suggestion(
+        parser_unexpected_token_after_not_bitwise,
+        style = "short",
         applicability = "machine-applicable",
         code = "!"
     )]
     SuggestNotBitwise(#[primary_span] Span),
 
-    #[suggestion_short(
-        parser::unexpected_token_after_not_logical,
+    #[suggestion(
+        parser_unexpected_token_after_not_logical,
+        style = "short",
         applicability = "machine-applicable",
         code = "!"
     )]
@@ -225,7 +227,7 @@ pub enum NotAsNegationOperatorSub {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::malformed_loop_label)]
+#[diag(parser_malformed_loop_label)]
 pub(crate) struct MalformedLoopLabel {
     #[primary_span]
     #[suggestion(applicability = "machine-applicable", code = "{correct_label}")]
@@ -234,7 +236,7 @@ pub(crate) struct MalformedLoopLabel {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::lifetime_in_borrow_expression)]
+#[diag(parser_lifetime_in_borrow_expression)]
 pub(crate) struct LifetimeInBorrowExpression {
     #[primary_span]
     pub span: Span,
@@ -244,27 +246,27 @@ pub(crate) struct LifetimeInBorrowExpression {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::field_expression_with_generic)]
+#[diag(parser_field_expression_with_generic)]
 pub(crate) struct FieldExpressionWithGeneric(#[primary_span] pub Span);
 
 #[derive(Diagnostic)]
-#[diag(parser::macro_invocation_with_qualified_path)]
+#[diag(parser_macro_invocation_with_qualified_path)]
 pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span);
 
 #[derive(Diagnostic)]
-#[diag(parser::unexpected_token_after_label)]
+#[diag(parser_unexpected_token_after_label)]
 pub(crate) struct UnexpectedTokenAfterLabel {
     #[primary_span]
-    #[label(parser::unexpected_token_after_label)]
+    #[label(parser_unexpected_token_after_label)]
     pub span: Span,
-    #[suggestion_verbose(parser::suggestion_remove_label, code = "")]
+    #[suggestion(suggestion_remove_label, style = "verbose", code = "")]
     pub remove_label: Option<Span>,
     #[subdiagnostic]
     pub enclose_in_block: Option<UnexpectedTokenAfterLabelSugg>,
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion_enclose_in_block, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion_enclose_in_block, applicability = "machine-applicable")]
 pub(crate) struct UnexpectedTokenAfterLabelSugg {
     #[suggestion_part(code = "{{ ")]
     pub left: Span,
@@ -273,19 +275,19 @@ pub(crate) struct UnexpectedTokenAfterLabelSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::require_colon_after_labeled_expression)]
+#[diag(parser_require_colon_after_labeled_expression)]
 #[note]
 pub(crate) struct RequireColonAfterLabeledExpression {
     #[primary_span]
     pub span: Span,
     #[label]
     pub label: Span,
-    #[suggestion_short(applicability = "machine-applicable", code = ": ")]
+    #[suggestion(style = "short", applicability = "machine-applicable", code = ": ")]
     pub label_end: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::do_catch_syntax_removed)]
+#[diag(parser_do_catch_syntax_removed)]
 #[note]
 pub(crate) struct DoCatchSyntaxRemoved {
     #[primary_span]
@@ -294,7 +296,7 @@ pub(crate) struct DoCatchSyntaxRemoved {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::float_literal_requires_integer_part)]
+#[diag(parser_float_literal_requires_integer_part)]
 pub(crate) struct FloatLiteralRequiresIntegerPart {
     #[primary_span]
     #[suggestion(applicability = "machine-applicable", code = "{correct}")]
@@ -303,7 +305,7 @@ pub(crate) struct FloatLiteralRequiresIntegerPart {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_int_literal_width)]
+#[diag(parser_invalid_int_literal_width)]
 #[help]
 pub(crate) struct InvalidIntLiteralWidth {
     #[primary_span]
@@ -312,7 +314,7 @@ pub(crate) struct InvalidIntLiteralWidth {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_num_literal_base_prefix)]
+#[diag(parser_invalid_num_literal_base_prefix)]
 #[note]
 pub(crate) struct InvalidNumLiteralBasePrefix {
     #[primary_span]
@@ -322,7 +324,7 @@ pub(crate) struct InvalidNumLiteralBasePrefix {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_num_literal_suffix)]
+#[diag(parser_invalid_num_literal_suffix)]
 #[help]
 pub(crate) struct InvalidNumLiteralSuffix {
     #[primary_span]
@@ -332,7 +334,7 @@ pub(crate) struct InvalidNumLiteralSuffix {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_float_literal_width)]
+#[diag(parser_invalid_float_literal_width)]
 #[help]
 pub(crate) struct InvalidFloatLiteralWidth {
     #[primary_span]
@@ -341,7 +343,7 @@ pub(crate) struct InvalidFloatLiteralWidth {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_float_literal_suffix)]
+#[diag(parser_invalid_float_literal_suffix)]
 #[help]
 pub(crate) struct InvalidFloatLiteralSuffix {
     #[primary_span]
@@ -351,23 +353,23 @@ pub(crate) struct InvalidFloatLiteralSuffix {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::int_literal_too_large)]
+#[diag(parser_int_literal_too_large)]
 pub(crate) struct IntLiteralTooLarge {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::missing_semicolon_before_array)]
+#[diag(parser_missing_semicolon_before_array)]
 pub(crate) struct MissingSemicolonBeforeArray {
     #[primary_span]
     pub open_delim: Span,
-    #[suggestion_verbose(applicability = "maybe-incorrect", code = ";")]
+    #[suggestion(style = "verbose", applicability = "maybe-incorrect", code = ";")]
     pub semicolon: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_block_macro_segment)]
+#[diag(parser_invalid_block_macro_segment)]
 pub(crate) struct InvalidBlockMacroSegment {
     #[primary_span]
     pub span: Span,
@@ -376,7 +378,7 @@ pub(crate) struct InvalidBlockMacroSegment {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::if_expression_missing_then_block)]
+#[diag(parser_if_expression_missing_then_block)]
 pub(crate) struct IfExpressionMissingThenBlock {
     #[primary_span]
     pub if_span: Span,
@@ -386,31 +388,31 @@ pub(crate) struct IfExpressionMissingThenBlock {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum IfExpressionMissingThenBlockSub {
-    #[help(parser::condition_possibly_unfinished)]
+    #[help(condition_possibly_unfinished)]
     UnfinishedCondition(#[primary_span] Span),
-    #[help(parser::add_then_block)]
+    #[help(add_then_block)]
     AddThenBlock(#[primary_span] Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::if_expression_missing_condition)]
+#[diag(parser_if_expression_missing_condition)]
 pub(crate) struct IfExpressionMissingCondition {
     #[primary_span]
-    #[label(parser::condition_label)]
+    #[label(condition_label)]
     pub if_span: Span,
-    #[label(parser::block_label)]
+    #[label(block_label)]
     pub block_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::expected_expression_found_let)]
+#[diag(parser_expected_expression_found_let)]
 pub(crate) struct ExpectedExpressionFoundLet {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::expected_else_block)]
+#[diag(parser_expected_else_block)]
 pub(crate) struct ExpectedElseBlock {
     #[primary_span]
     pub first_tok_span: Span,
@@ -422,15 +424,15 @@ pub(crate) struct ExpectedElseBlock {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::outer_attribute_not_allowed_on_if_else)]
+#[diag(parser_outer_attribute_not_allowed_on_if_else)]
 pub(crate) struct OuterAttributeNotAllowedOnIfElse {
     #[primary_span]
     pub last: Span,
 
-    #[label(parser::branch_label)]
+    #[label(branch_label)]
     pub branch_span: Span,
 
-    #[label(parser::ctx_label)]
+    #[label(ctx_label)]
     pub ctx_span: Span,
     pub ctx: String,
 
@@ -439,7 +441,7 @@ pub(crate) struct OuterAttributeNotAllowedOnIfElse {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::missing_in_in_for_loop)]
+#[diag(parser_missing_in_in_for_loop)]
 pub(crate) struct MissingInInForLoop {
     #[primary_span]
     pub span: Span,
@@ -450,14 +452,14 @@ pub(crate) struct MissingInInForLoop {
 #[derive(Subdiagnostic)]
 pub(crate) enum MissingInInForLoopSub {
     // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect
-    #[suggestion_short(parser::use_in_not_of, applicability = "maybe-incorrect", code = "in")]
+    #[suggestion(use_in_not_of, style = "short", applicability = "maybe-incorrect", code = "in")]
     InNotOf(#[primary_span] Span),
-    #[suggestion_short(parser::add_in, applicability = "maybe-incorrect", code = " in ")]
+    #[suggestion(add_in, style = "short", applicability = "maybe-incorrect", code = " in ")]
     AddIn(#[primary_span] Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::missing_comma_after_match_arm)]
+#[diag(parser_missing_comma_after_match_arm)]
 pub(crate) struct MissingCommaAfterMatchArm {
     #[primary_span]
     #[suggestion(applicability = "machine-applicable", code = ",")]
@@ -465,7 +467,7 @@ pub(crate) struct MissingCommaAfterMatchArm {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::catch_after_try)]
+#[diag(parser_catch_after_try)]
 #[help]
 pub(crate) struct CatchAfterTry {
     #[primary_span]
@@ -473,17 +475,17 @@ pub(crate) struct CatchAfterTry {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::comma_after_base_struct)]
+#[diag(parser_comma_after_base_struct)]
 #[note]
 pub(crate) struct CommaAfterBaseStruct {
     #[primary_span]
     pub span: Span,
-    #[suggestion_short(applicability = "machine-applicable", code = "")]
+    #[suggestion(style = "short", applicability = "machine-applicable", code = "")]
     pub comma: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::eq_field_init)]
+#[diag(parser_eq_field_init)]
 pub(crate) struct EqFieldInit {
     #[primary_span]
     pub span: Span,
@@ -492,16 +494,16 @@ pub(crate) struct EqFieldInit {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::dotdotdot)]
+#[diag(parser_dotdotdot)]
 pub(crate) struct DotDotDot {
     #[primary_span]
-    #[suggestion(parser::suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
-    #[suggestion(parser::suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
+    #[suggestion(suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
+    #[suggestion(suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::left_arrow_operator)]
+#[diag(parser_left_arrow_operator)]
 pub(crate) struct LeftArrowOperator {
     #[primary_span]
     #[suggestion(applicability = "maybe-incorrect", code = "< -")]
@@ -509,7 +511,7 @@ pub(crate) struct LeftArrowOperator {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::remove_let)]
+#[diag(parser_remove_let)]
 pub(crate) struct RemoveLet {
     #[primary_span]
     #[suggestion(applicability = "machine-applicable", code = "")]
@@ -517,49 +519,49 @@ pub(crate) struct RemoveLet {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::use_eq_instead)]
+#[diag(parser_use_eq_instead)]
 pub(crate) struct UseEqInstead {
     #[primary_span]
-    #[suggestion_short(applicability = "machine-applicable", code = "=")]
+    #[suggestion(style = "short", applicability = "machine-applicable", code = "=")]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::use_empty_block_not_semi)]
+#[diag(parser_use_empty_block_not_semi)]
 pub(crate) struct UseEmptyBlockNotSemi {
     #[primary_span]
-    #[suggestion_hidden(applicability = "machine-applicable", code = "{{}}")]
+    #[suggestion(style = "hidden", applicability = "machine-applicable", code = "{{}}")]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::comparison_interpreted_as_generic)]
+#[diag(parser_comparison_interpreted_as_generic)]
 pub(crate) struct ComparisonInterpretedAsGeneric {
     #[primary_span]
-    #[label(parser::label_comparison)]
+    #[label(label_comparison)]
     pub comparison: Span,
     pub r#type: Path,
-    #[label(parser::label_args)]
+    #[label(label_args)]
     pub args: Span,
     #[subdiagnostic]
     pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::shift_interpreted_as_generic)]
+#[diag(parser_shift_interpreted_as_generic)]
 pub(crate) struct ShiftInterpretedAsGeneric {
     #[primary_span]
-    #[label(parser::label_comparison)]
+    #[label(label_comparison)]
     pub shift: Span,
     pub r#type: Path,
-    #[label(parser::label_args)]
+    #[label(label_args)]
     pub args: Span,
     #[subdiagnostic]
     pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg,
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct ComparisonOrShiftInterpretedAsGenericSugg {
     #[suggestion_part(code = "(")]
     pub left: Span,
@@ -568,7 +570,7 @@ pub(crate) struct ComparisonOrShiftInterpretedAsGenericSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::found_expr_would_be_stmt)]
+#[diag(parser_found_expr_would_be_stmt)]
 pub(crate) struct FoundExprWouldBeStmt {
     #[primary_span]
     #[label]
@@ -579,13 +581,14 @@ pub(crate) struct FoundExprWouldBeStmt {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::leading_plus_not_supported)]
+#[diag(parser_leading_plus_not_supported)]
 pub(crate) struct LeadingPlusNotSupported {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[suggestion_verbose(
-        parser::suggestion_remove_plus,
+    #[suggestion(
+        suggestion_remove_plus,
+        style = "verbose",
         code = "",
         applicability = "machine-applicable"
     )]
@@ -595,7 +598,7 @@ pub(crate) struct LeadingPlusNotSupported {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::parentheses_with_struct_fields)]
+#[diag(parser_parentheses_with_struct_fields)]
 pub(crate) struct ParenthesesWithStructFields {
     #[primary_span]
     pub span: Span,
@@ -607,7 +610,7 @@ pub(crate) struct ParenthesesWithStructFields {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion_braces_for_struct, applicability = "maybe-incorrect")]
+#[multipart_suggestion(suggestion_braces_for_struct, applicability = "maybe-incorrect")]
 pub(crate) struct BracesForStructLiteral {
     #[suggestion_part(code = " {{ ")]
     pub first: Span,
@@ -616,14 +619,14 @@ pub(crate) struct BracesForStructLiteral {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion_no_fields_for_fn, applicability = "maybe-incorrect")]
+#[multipart_suggestion(suggestion_no_fields_for_fn, applicability = "maybe-incorrect")]
 pub(crate) struct NoFieldsForFnCall {
     #[suggestion_part(code = "")]
     pub fields: Vec<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::labeled_loop_in_break)]
+#[diag(parser_labeled_loop_in_break)]
 pub(crate) struct LabeledLoopInBreak {
     #[primary_span]
     pub span: Span,
@@ -633,7 +636,7 @@ pub(crate) struct LabeledLoopInBreak {
 
 #[derive(Subdiagnostic)]
 #[multipart_suggestion(
-    parser::sugg_wrap_expression_in_parentheses,
+    parser_sugg_wrap_expression_in_parentheses,
     applicability = "machine-applicable"
 )]
 pub(crate) struct WrapExpressionInParentheses {
@@ -644,7 +647,7 @@ pub(crate) struct WrapExpressionInParentheses {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::array_brackets_instead_of_braces)]
+#[diag(parser_array_brackets_instead_of_braces)]
 pub(crate) struct ArrayBracketsInsteadOfSpaces {
     #[primary_span]
     pub span: Span,
@@ -653,7 +656,7 @@ pub(crate) struct ArrayBracketsInsteadOfSpaces {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "maybe-incorrect")]
+#[multipart_suggestion(suggestion, applicability = "maybe-incorrect")]
 pub(crate) struct ArrayBracketsInsteadOfSpacesSugg {
     #[suggestion_part(code = "[")]
     pub left: Span,
@@ -662,12 +665,12 @@ pub(crate) struct ArrayBracketsInsteadOfSpacesSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::match_arm_body_without_braces)]
+#[diag(parser_match_arm_body_without_braces)]
 pub(crate) struct MatchArmBodyWithoutBraces {
     #[primary_span]
-    #[label(parser::label_statements)]
+    #[label(label_statements)]
     pub statements: Span,
-    #[label(parser::label_arrow)]
+    #[label(label_arrow)]
     pub arrow: Span,
     pub num_statements: usize,
     #[subdiagnostic]
@@ -676,7 +679,7 @@ pub(crate) struct MatchArmBodyWithoutBraces {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum MatchArmBodyWithoutBracesSugg {
-    #[multipart_suggestion(parser::suggestion_add_braces, applicability = "machine-applicable")]
+    #[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")]
     AddBraces {
         #[suggestion_part(code = "{{ ")]
         left: Span,
@@ -684,7 +687,7 @@ pub(crate) enum MatchArmBodyWithoutBracesSugg {
         right: Span,
     },
     #[suggestion(
-        parser::suggestion_use_comma_not_semicolon,
+        suggestion_use_comma_not_semicolon,
         code = ",",
         applicability = "machine-applicable"
     )]
@@ -695,7 +698,7 @@ pub(crate) enum MatchArmBodyWithoutBracesSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::struct_literal_not_allowed_here)]
+#[diag(parser_struct_literal_not_allowed_here)]
 pub(crate) struct StructLiteralNotAllowedHere {
     #[primary_span]
     pub span: Span,
@@ -704,7 +707,7 @@ pub(crate) struct StructLiteralNotAllowedHere {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct StructLiteralNotAllowedHereSugg {
     #[suggestion_part(code = "(")]
     pub left: Span,
@@ -713,38 +716,38 @@ pub(crate) struct StructLiteralNotAllowedHereSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_interpolated_expression)]
+#[diag(parser_invalid_interpolated_expression)]
 pub(crate) struct InvalidInterpolatedExpression {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::hexadecimal_float_literal_not_supported)]
+#[diag(parser_hexadecimal_float_literal_not_supported)]
 pub(crate) struct HexadecimalFloatLiteralNotSupported {
     #[primary_span]
-    #[label(parser::not_supported)]
+    #[label(parser_not_supported)]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::octal_float_literal_not_supported)]
+#[diag(parser_octal_float_literal_not_supported)]
 pub(crate) struct OctalFloatLiteralNotSupported {
     #[primary_span]
-    #[label(parser::not_supported)]
+    #[label(parser_not_supported)]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::binary_float_literal_not_supported)]
+#[diag(parser_binary_float_literal_not_supported)]
 pub(crate) struct BinaryFloatLiteralNotSupported {
     #[primary_span]
-    #[label(parser::not_supported)]
+    #[label(parser_not_supported)]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_literal_suffix)]
+#[diag(parser_invalid_literal_suffix)]
 pub(crate) struct InvalidLiteralSuffix {
     #[primary_span]
     #[label]
@@ -755,20 +758,20 @@ pub(crate) struct InvalidLiteralSuffix {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_literal_suffix_on_tuple_index)]
+#[diag(parser_invalid_literal_suffix_on_tuple_index)]
 pub(crate) struct InvalidLiteralSuffixOnTupleIndex {
     #[primary_span]
     #[label]
     pub span: Span,
     pub suffix: Symbol,
-    #[help(parser::tuple_exception_line_1)]
-    #[help(parser::tuple_exception_line_2)]
-    #[help(parser::tuple_exception_line_3)]
+    #[help(tuple_exception_line_1)]
+    #[help(tuple_exception_line_2)]
+    #[help(tuple_exception_line_3)]
     pub exception: Option<()>,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::non_string_abi_literal)]
+#[diag(parser_non_string_abi_literal)]
 pub(crate) struct NonStringAbiLiteral {
     #[primary_span]
     #[suggestion(code = "\"C\"", applicability = "maybe-incorrect")]
@@ -776,21 +779,21 @@ pub(crate) struct NonStringAbiLiteral {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::mismatched_closing_delimiter)]
+#[diag(parser_mismatched_closing_delimiter)]
 pub(crate) struct MismatchedClosingDelimiter {
     #[primary_span]
     pub spans: Vec<Span>,
     pub delimiter: String,
-    #[label(parser::label_unmatched)]
+    #[label(label_unmatched)]
     pub unmatched: Span,
-    #[label(parser::label_opening_candidate)]
+    #[label(label_opening_candidate)]
     pub opening_candidate: Option<Span>,
-    #[label(parser::label_unclosed)]
+    #[label(label_unclosed)]
     pub unclosed: Option<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::incorrect_visibility_restriction, code = "E0704")]
+#[diag(parser_incorrect_visibility_restriction, code = "E0704")]
 #[help]
 pub(crate) struct IncorrectVisibilityRestriction {
     #[primary_span]
@@ -800,21 +803,21 @@ pub(crate) struct IncorrectVisibilityRestriction {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::assignment_else_not_allowed)]
+#[diag(parser_assignment_else_not_allowed)]
 pub(crate) struct AssignmentElseNotAllowed {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::expected_statement_after_outer_attr)]
+#[diag(parser_expected_statement_after_outer_attr)]
 pub(crate) struct ExpectedStatementAfterOuterAttr {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::doc_comment_does_not_document_anything, code = "E0585")]
+#[diag(parser_doc_comment_does_not_document_anything, code = "E0585")]
 #[help]
 pub(crate) struct DocCommentDoesNotDocumentAnything {
     #[primary_span]
@@ -824,7 +827,7 @@ pub(crate) struct DocCommentDoesNotDocumentAnything {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::const_let_mutually_exclusive)]
+#[diag(parser_const_let_mutually_exclusive)]
 pub(crate) struct ConstLetMutuallyExclusive {
     #[primary_span]
     #[suggestion(code = "const", applicability = "maybe-incorrect")]
@@ -832,7 +835,7 @@ pub(crate) struct ConstLetMutuallyExclusive {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_expression_in_let_else)]
+#[diag(parser_invalid_expression_in_let_else)]
 pub(crate) struct InvalidExpressionInLetElse {
     #[primary_span]
     pub span: Span,
@@ -842,7 +845,7 @@ pub(crate) struct InvalidExpressionInLetElse {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_curly_in_let_else)]
+#[diag(parser_invalid_curly_in_let_else)]
 pub(crate) struct InvalidCurlyInLetElse {
     #[primary_span]
     pub span: Span,
@@ -851,16 +854,16 @@ pub(crate) struct InvalidCurlyInLetElse {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::compound_assignment_expression_in_let)]
+#[diag(parser_compound_assignment_expression_in_let)]
 #[help]
 pub(crate) struct CompoundAssignmentExpressionInLet {
     #[primary_span]
-    #[suggestion_short(code = "=", applicability = "maybe-incorrect")]
+    #[suggestion(style = "short", code = "=", applicability = "maybe-incorrect")]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::suffixed_literal_in_attribute)]
+#[diag(parser_suffixed_literal_in_attribute)]
 #[help]
 pub(crate) struct SuffixedLiteralInAttribute {
     #[primary_span]
@@ -868,7 +871,7 @@ pub(crate) struct SuffixedLiteralInAttribute {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_meta_item)]
+#[diag(parser_invalid_meta_item)]
 pub(crate) struct InvalidMetaItem {
     #[primary_span]
     pub span: Span,
@@ -876,8 +879,9 @@ pub(crate) struct InvalidMetaItem {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion_verbose(
-    parser::sugg_escape_to_use_as_identifier,
+#[suggestion(
+    parser_sugg_escape_to_use_as_identifier,
+    style = "verbose",
     applicability = "maybe-incorrect",
     code = "r#"
 )]
@@ -888,7 +892,7 @@ pub(crate) struct SuggEscapeToUseAsIdentifier {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::sugg_remove_comma, applicability = "machine-applicable", code = "")]
+#[suggestion(parser_sugg_remove_comma, applicability = "machine-applicable", code = "")]
 pub(crate) struct SuggRemoveComma {
     #[primary_span]
     pub span: Span,
@@ -896,15 +900,15 @@ pub(crate) struct SuggRemoveComma {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum ExpectedIdentifierFound {
-    #[label(parser::expected_identifier_found_reserved_identifier)]
+    #[label(parser_expected_identifier_found_reserved_identifier)]
     ReservedIdentifier(#[primary_span] Span),
-    #[label(parser::expected_identifier_found_keyword)]
+    #[label(parser_expected_identifier_found_keyword)]
     Keyword(#[primary_span] Span),
-    #[label(parser::expected_identifier_found_reserved_keyword)]
+    #[label(parser_expected_identifier_found_reserved_keyword)]
     ReservedKeyword(#[primary_span] Span),
-    #[label(parser::expected_identifier_found_doc_comment)]
+    #[label(parser_expected_identifier_found_doc_comment)]
     DocComment(#[primary_span] Span),
-    #[label(parser::expected_identifier)]
+    #[label(parser_expected_identifier)]
     Other(#[primary_span] Span),
 }
 
@@ -930,6 +934,7 @@ pub(crate) struct ExpectedIdentifier {
 }
 
 impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
+    #[track_caller]
     fn into_diagnostic(
         self,
         handler: &'a rustc_errors::Handler,
@@ -938,18 +943,16 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
 
         let mut diag = handler.struct_diagnostic(match token_descr {
             Some(TokenDescription::ReservedIdentifier) => {
-                fluent::parser::expected_identifier_found_reserved_identifier_str
-            }
-            Some(TokenDescription::Keyword) => {
-                fluent::parser::expected_identifier_found_keyword_str
+                fluent::parser_expected_identifier_found_reserved_identifier_str
             }
+            Some(TokenDescription::Keyword) => fluent::parser_expected_identifier_found_keyword_str,
             Some(TokenDescription::ReservedKeyword) => {
-                fluent::parser::expected_identifier_found_reserved_keyword_str
+                fluent::parser_expected_identifier_found_reserved_keyword_str
             }
             Some(TokenDescription::DocComment) => {
-                fluent::parser::expected_identifier_found_doc_comment_str
+                fluent::parser_expected_identifier_found_doc_comment_str
             }
-            None => fluent::parser::expected_identifier_found_str,
+            None => fluent::parser_expected_identifier_found_str,
         });
         diag.set_span(self.span);
         diag.set_arg("token", self.token);
@@ -977,6 +980,7 @@ pub(crate) struct ExpectedSemi {
 }
 
 impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi {
+    #[track_caller]
     fn into_diagnostic(
         self,
         handler: &'a rustc_errors::Handler,
@@ -985,22 +989,22 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi {
 
         let mut diag = handler.struct_diagnostic(match token_descr {
             Some(TokenDescription::ReservedIdentifier) => {
-                fluent::parser::expected_semi_found_reserved_identifier_str
+                fluent::parser_expected_semi_found_reserved_identifier_str
             }
-            Some(TokenDescription::Keyword) => fluent::parser::expected_semi_found_keyword_str,
+            Some(TokenDescription::Keyword) => fluent::parser_expected_semi_found_keyword_str,
             Some(TokenDescription::ReservedKeyword) => {
-                fluent::parser::expected_semi_found_reserved_keyword_str
+                fluent::parser_expected_semi_found_reserved_keyword_str
             }
             Some(TokenDescription::DocComment) => {
-                fluent::parser::expected_semi_found_doc_comment_str
+                fluent::parser_expected_semi_found_doc_comment_str
             }
-            None => fluent::parser::expected_semi_found_str,
+            None => fluent::parser_expected_semi_found_str,
         });
         diag.set_span(self.span);
         diag.set_arg("token", self.token);
 
         if let Some(unexpected_token_label) = self.unexpected_token_label {
-            diag.span_label(unexpected_token_label, fluent::parser::label_unexpected_token);
+            diag.span_label(unexpected_token_label, fluent::parser_label_unexpected_token);
         }
 
         self.sugg.add_to_diagnostic(&mut diag);
@@ -1012,17 +1016,22 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi {
 #[derive(Subdiagnostic)]
 pub(crate) enum ExpectedSemiSugg {
     #[suggestion(
-        parser::sugg_change_this_to_semi,
+        parser_sugg_change_this_to_semi,
         code = ";",
         applicability = "machine-applicable"
     )]
     ChangeToSemi(#[primary_span] Span),
-    #[suggestion_short(parser::sugg_add_semi, code = ";", applicability = "machine-applicable")]
+    #[suggestion(
+        parser_sugg_add_semi,
+        style = "short",
+        code = ";",
+        applicability = "machine-applicable"
+    )]
     AddSemi(#[primary_span] Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::struct_literal_body_without_path)]
+#[diag(parser_struct_literal_body_without_path)]
 pub(crate) struct StructLiteralBodyWithoutPath {
     #[primary_span]
     pub span: Span,
@@ -1031,7 +1040,7 @@ pub(crate) struct StructLiteralBodyWithoutPath {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "has-placeholders")]
+#[multipart_suggestion(suggestion, applicability = "has-placeholders")]
 pub(crate) struct StructLiteralBodyWithoutPathSugg {
     #[suggestion_part(code = "{{ SomeStruct ")]
     pub before: Span,
@@ -1040,7 +1049,7 @@ pub(crate) struct StructLiteralBodyWithoutPathSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::unmatched_angle_brackets)]
+#[diag(parser_unmatched_angle_brackets)]
 pub(crate) struct UnmatchedAngleBrackets {
     #[primary_span]
     #[suggestion(code = "", applicability = "machine-applicable")]
@@ -1049,7 +1058,7 @@ pub(crate) struct UnmatchedAngleBrackets {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::generic_parameters_without_angle_brackets)]
+#[diag(parser_generic_parameters_without_angle_brackets)]
 pub(crate) struct GenericParamsWithoutAngleBrackets {
     #[primary_span]
     pub span: Span,
@@ -1058,7 +1067,7 @@ pub(crate) struct GenericParamsWithoutAngleBrackets {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct GenericParamsWithoutAngleBracketsSugg {
     #[suggestion_part(code = "<")]
     pub left: Span,
@@ -1067,18 +1076,19 @@ pub(crate) struct GenericParamsWithoutAngleBracketsSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::comparison_operators_cannot_be_chained)]
+#[diag(parser_comparison_operators_cannot_be_chained)]
 pub(crate) struct ComparisonOperatorsCannotBeChained {
     #[primary_span]
     pub span: Vec<Span>,
-    #[suggestion_verbose(
-        parser::sugg_turbofish_syntax,
+    #[suggestion(
+        parser_sugg_turbofish_syntax,
+        style = "verbose",
         code = "::",
         applicability = "maybe-incorrect"
     )]
     pub suggest_turbofish: Option<Span>,
-    #[help(parser::sugg_turbofish_syntax)]
-    #[help(parser::sugg_parentheses_for_function_args)]
+    #[help(parser_sugg_turbofish_syntax)]
+    #[help(sugg_parentheses_for_function_args)]
     pub help_turbofish: Option<()>,
     #[subdiagnostic]
     pub chaining_sugg: Option<ComparisonOperatorsCannotBeChainedSugg>,
@@ -1086,8 +1096,9 @@ pub(crate) struct ComparisonOperatorsCannotBeChained {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum ComparisonOperatorsCannotBeChainedSugg {
-    #[suggestion_verbose(
-        parser::sugg_split_comparison,
+    #[suggestion(
+        sugg_split_comparison,
+        style = "verbose",
         code = " && {middle_term}",
         applicability = "maybe-incorrect"
     )]
@@ -1096,7 +1107,7 @@ pub(crate) enum ComparisonOperatorsCannotBeChainedSugg {
         span: Span,
         middle_term: String,
     },
-    #[multipart_suggestion(parser::sugg_parenthesize, applicability = "maybe-incorrect")]
+    #[multipart_suggestion(sugg_parenthesize, applicability = "maybe-incorrect")]
     Parenthesize {
         #[suggestion_part(code = "(")]
         left: Span,
@@ -1106,7 +1117,7 @@ pub(crate) enum ComparisonOperatorsCannotBeChainedSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::question_mark_in_type)]
+#[diag(parser_question_mark_in_type)]
 pub(crate) struct QuestionMarkInType {
     #[primary_span]
     #[label]
@@ -1116,7 +1127,7 @@ pub(crate) struct QuestionMarkInType {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct QuestionMarkInTypeSugg {
     #[suggestion_part(code = "Option<")]
     pub left: Span,
@@ -1125,7 +1136,7 @@ pub(crate) struct QuestionMarkInTypeSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::unexpected_parentheses_in_for_head)]
+#[diag(parser_unexpected_parentheses_in_for_head)]
 pub(crate) struct ParenthesesInForHead {
     #[primary_span]
     pub span: Vec<Span>,
@@ -1134,7 +1145,7 @@ pub(crate) struct ParenthesesInForHead {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct ParenthesesInForHeadSugg {
     #[suggestion_part(code = "")]
     pub left: Span,
@@ -1143,7 +1154,7 @@ pub(crate) struct ParenthesesInForHeadSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::doc_comment_on_param_type)]
+#[diag(parser_doc_comment_on_param_type)]
 pub(crate) struct DocCommentOnParamType {
     #[primary_span]
     #[label]
@@ -1151,7 +1162,7 @@ pub(crate) struct DocCommentOnParamType {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::attribute_on_param_type)]
+#[diag(parser_attribute_on_param_type)]
 pub(crate) struct AttributeOnParamType {
     #[primary_span]
     #[label]
@@ -1159,7 +1170,7 @@ pub(crate) struct AttributeOnParamType {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::pattern_method_param_without_body, code = "E0642")]
+#[diag(parser_pattern_method_param_without_body, code = "E0642")]
 pub(crate) struct PatternMethodParamWithoutBody {
     #[primary_span]
     #[suggestion(code = "_", applicability = "machine-applicable")]
@@ -1167,7 +1178,7 @@ pub(crate) struct PatternMethodParamWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::self_param_not_first)]
+#[diag(parser_self_param_not_first)]
 pub(crate) struct SelfParamNotFirst {
     #[primary_span]
     #[label]
@@ -1175,7 +1186,7 @@ pub(crate) struct SelfParamNotFirst {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::const_generic_without_braces)]
+#[diag(parser_const_generic_without_braces)]
 pub(crate) struct ConstGenericWithoutBraces {
     #[primary_span]
     pub span: Span,
@@ -1184,7 +1195,7 @@ pub(crate) struct ConstGenericWithoutBraces {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct ConstGenericWithoutBracesSugg {
     #[suggestion_part(code = "{{ ")]
     pub left: Span,
@@ -1193,7 +1204,7 @@ pub(crate) struct ConstGenericWithoutBracesSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::unexpected_const_param_declaration)]
+#[diag(parser_unexpected_const_param_declaration)]
 pub(crate) struct UnexpectedConstParamDeclaration {
     #[primary_span]
     #[label]
@@ -1204,7 +1215,7 @@ pub(crate) struct UnexpectedConstParamDeclaration {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum UnexpectedConstParamDeclarationSugg {
-    #[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+    #[multipart_suggestion(suggestion, applicability = "machine-applicable")]
     AddParam {
         #[suggestion_part(code = "<{snippet}>")]
         impl_generics: Span,
@@ -1213,7 +1224,7 @@ pub(crate) enum UnexpectedConstParamDeclarationSugg {
         snippet: String,
         ident: String,
     },
-    #[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+    #[multipart_suggestion(suggestion, applicability = "machine-applicable")]
     AppendParam {
         #[suggestion_part(code = ", {snippet}")]
         impl_generics_end: Span,
@@ -1225,24 +1236,24 @@ pub(crate) enum UnexpectedConstParamDeclarationSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::unexpected_const_in_generic_param)]
+#[diag(parser_unexpected_const_in_generic_param)]
 pub(crate) struct UnexpectedConstInGenericParam {
     #[primary_span]
     pub span: Span,
-    #[suggestion_verbose(code = "", applicability = "maybe-incorrect")]
+    #[suggestion(style = "verbose", code = "", applicability = "maybe-incorrect")]
     pub to_remove: Option<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::async_move_order_incorrect)]
+#[diag(parser_async_move_order_incorrect)]
 pub(crate) struct AsyncMoveOrderIncorrect {
     #[primary_span]
-    #[suggestion_verbose(code = "async move", applicability = "maybe-incorrect")]
+    #[suggestion(style = "verbose", code = "async move", applicability = "maybe-incorrect")]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::double_colon_in_bound)]
+#[diag(parser_double_colon_in_bound)]
 pub(crate) struct DoubleColonInBound {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 88540e13ef2..462bce16ad7 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -3,7 +3,9 @@ use rustc_ast::ast::{self, AttrStyle};
 use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::util::unicode::contains_text_flow_control_chars;
-use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
+use rustc_errors::{
+    error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult, StashKey,
+};
 use rustc_lexer::unescape::{self, Mode};
 use rustc_lexer::Cursor;
 use rustc_lexer::{Base, DocStyle, RawStrError};
@@ -203,7 +205,10 @@ impl<'a> StringReader<'a> {
                     // this is necessary.
                     let lifetime_name = self.str_from(start);
                     if starts_with_number {
-                        self.err_span_(start, self.pos, "lifetimes cannot start with a number");
+                        let span = self.mk_sp(start, self.pos);
+                        let mut diag = self.sess.struct_err("lifetimes cannot start with a number");
+                        diag.set_span(span);
+                        diag.stash(span, StashKey::LifetimeIsChar);
                     }
                     let ident = Symbol::intern(lifetime_name);
                     token::Lifetime(ident)
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 77c4fadab45..f075de71426 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -113,11 +113,26 @@ pub(crate) fn emit_unescape_error(
                 } else {
                     ("", "if you meant to write a `str` literal, use double quotes")
                 };
-
+                let mut escaped = String::with_capacity(lit.len());
+                let mut chrs = lit.chars().peekable();
+                while let Some(first) = chrs.next() {
+                    match (first, chrs.peek()) {
+                        ('\\', Some('"')) => {
+                            escaped.push('\\');
+                            escaped.push('"');
+                            chrs.next();
+                        }
+                        ('"', _) => {
+                            escaped.push('\\');
+                            escaped.push('"')
+                        }
+                        (c, _) => escaped.push(c),
+                    };
+                }
                 handler.span_suggestion(
                     span_with_quotes,
                     msg,
-                    format!("{}\"{}\"", prefix, lit),
+                    format!("{prefix}\"{escaped}\""),
                     Applicability::MachineApplicable,
                 );
             }
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 58be348883c..9e45656946b 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -55,7 +55,7 @@ impl<'a> Parser<'a> {
                     let span = self.token.span;
                     let mut err = self.sess.span_diagnostic.struct_span_err_with_code(
                         span,
-                        fluent::parser::inner_doc_comment_not_permitted,
+                        fluent::parser_inner_doc_comment_not_permitted,
                         error_code!(E0753),
                     );
                     if let Some(replacement_span) = self.annotate_following_item_if_applicable(
@@ -66,10 +66,10 @@ impl<'a> Parser<'a> {
                             token::CommentKind::Block => OuterAttributeType::DocBlockComment,
                         },
                     ) {
-                        err.note(fluent::parser::note);
+                        err.note(fluent::note);
                         err.span_suggestion_verbose(
                             replacement_span,
-                            fluent::parser::suggestion,
+                            fluent::suggestion,
                             "",
                             rustc_errors::Applicability::MachineApplicable,
                         );
@@ -173,10 +173,10 @@ impl<'a> Parser<'a> {
             Ok(Some(item)) => {
                 // FIXME(#100717)
                 err.set_arg("item", item.kind.descr());
-                err.span_label(item.span, fluent::parser::label_does_not_annotate_this);
+                err.span_label(item.span, fluent::label_does_not_annotate_this);
                 err.span_suggestion_verbose(
                     replacement_span,
-                    fluent::parser::sugg_change_inner_to_outer,
+                    fluent::sugg_change_inner_to_outer,
                     match attr_type {
                         OuterAttributeType::Attribute => "",
                         OuterAttributeType::DocBlockComment => "*",
@@ -200,27 +200,27 @@ impl<'a> Parser<'a> {
                 Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => {
                     let mut diag = self.struct_span_err(
                         attr_sp,
-                        fluent::parser::inner_attr_not_permitted_after_outer_doc_comment,
+                        fluent::parser_inner_attr_not_permitted_after_outer_doc_comment,
                     );
-                    diag.span_label(attr_sp, fluent::parser::label_attr)
-                        .span_label(prev_doc_comment_span, fluent::parser::label_prev_doc_comment);
+                    diag.span_label(attr_sp, fluent::label_attr)
+                        .span_label(prev_doc_comment_span, fluent::label_prev_doc_comment);
                     diag
                 }
                 Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => {
                     let mut diag = self.struct_span_err(
                         attr_sp,
-                        fluent::parser::inner_attr_not_permitted_after_outer_attr,
+                        fluent::parser_inner_attr_not_permitted_after_outer_attr,
                     );
-                    diag.span_label(attr_sp, fluent::parser::label_attr)
-                        .span_label(prev_outer_attr_sp, fluent::parser::label_prev_attr);
+                    diag.span_label(attr_sp, fluent::label_attr)
+                        .span_label(prev_outer_attr_sp, fluent::label_prev_attr);
                     diag
                 }
                 Some(InnerAttrForbiddenReason::InCodeBlock) | None => {
-                    self.struct_span_err(attr_sp, fluent::parser::inner_attr_not_permitted)
+                    self.struct_span_err(attr_sp, fluent::parser_inner_attr_not_permitted)
                 }
             };
 
-            diag.note(fluent::parser::inner_attr_explanation);
+            diag.note(fluent::parser_inner_attr_explanation);
             if self
                 .annotate_following_item_if_applicable(
                     &mut diag,
@@ -229,7 +229,7 @@ impl<'a> Parser<'a> {
                 )
                 .is_some()
             {
-                diag.note(fluent::parser::outer_attr_explanation);
+                diag.note(fluent::parser_outer_attr_explanation);
             };
             diag.emit();
         }
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 81c051b8f35..1b16ecb5ec2 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -273,16 +273,23 @@ impl<'a> Parser<'a> {
         let cursor_snapshot_next_calls = cursor_snapshot.num_next_calls;
         let mut end_pos = self.token_cursor.num_next_calls;
 
+        let mut captured_trailing = false;
+
         // Capture a trailing token if requested by the callback 'f'
         match trailing {
             TrailingToken::None => {}
+            TrailingToken::Gt => {
+                assert_eq!(self.token.kind, token::Gt);
+            }
             TrailingToken::Semi => {
                 assert_eq!(self.token.kind, token::Semi);
                 end_pos += 1;
+                captured_trailing = true;
             }
             TrailingToken::MaybeComma => {
                 if self.token.kind == token::Comma {
                     end_pos += 1;
+                    captured_trailing = true;
                 }
             }
         }
@@ -292,11 +299,7 @@ impl<'a> Parser<'a> {
         // was not actually bumped past it. When the `LazyAttrTokenStream` gets converted
         // into an `AttrTokenStream`, we will create the proper token.
         if self.token_cursor.break_last_token {
-            assert_eq!(
-                trailing,
-                TrailingToken::None,
-                "Cannot set `break_last_token` and have trailing token"
-            );
+            assert!(!captured_trailing, "Cannot set break_last_token and have trailing token");
             end_pos += 1;
         }
 
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index f57bd9cec19..7dc4fd0044f 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -769,6 +769,10 @@ impl<'a> Parser<'a> {
         segment: &PathSegment,
         end: &[&TokenKind],
     ) -> bool {
+        if !self.may_recover() {
+            return false;
+        }
+
         // This function is intended to be invoked after parsing a path segment where there are two
         // cases:
         //
@@ -863,6 +867,10 @@ impl<'a> Parser<'a> {
     /// Check if a method call with an intended turbofish has been written without surrounding
     /// angle brackets.
     pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut PathSegment) {
+        if !self.may_recover() {
+            return;
+        }
+
         if token::ModSep == self.token.kind && segment.args.is_none() {
             let snapshot = self.create_snapshot_for_diagnostic();
             self.bump();
@@ -926,7 +934,7 @@ impl<'a> Parser<'a> {
                     if self.eat(&token::Gt) {
                         e.span_suggestion_verbose(
                             binop.span.shrink_to_lo(),
-                            fluent::parser::sugg_turbofish_syntax,
+                            fluent::parser_sugg_turbofish_syntax,
                             "::",
                             Applicability::MaybeIncorrect,
                         )
@@ -1374,9 +1382,17 @@ impl<'a> Parser<'a> {
         kind: IncDecRecovery,
         (pre_span, post_span): (Span, Span),
     ) -> MultiSugg {
+        let mut patches = Vec::new();
+
+        if !pre_span.is_empty() {
+            patches.push((pre_span, String::new()));
+        }
+
+        patches.push((post_span, format!(" {}= 1", kind.op.chr())));
+
         MultiSugg {
             msg: format!("use `{}= 1` instead", kind.op.chr()),
-            patches: vec![(pre_span, String::new()), (post_span, format!(" {}= 1", kind.op.chr()))],
+            patches,
             applicability: Applicability::MachineApplicable,
         }
     }
@@ -1388,6 +1404,10 @@ impl<'a> Parser<'a> {
         &mut self,
         base: P<T>,
     ) -> PResult<'a, P<T>> {
+        if !self.may_recover() {
+            return Ok(base);
+        }
+
         // Do not add `::` to expected tokens.
         if self.token == token::ModSep {
             if let Some(ty) = base.to_ty() {
@@ -1461,7 +1481,7 @@ impl<'a> Parser<'a> {
         let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {
             // Point at the end of the macro call when reaching end of macro arguments.
             (token::Eof, Some(_)) => {
-                let sp = self.sess.source_map().next_point(self.prev_token.span);
+                let sp = self.prev_token.span.shrink_to_hi();
                 (sp, sp)
             }
             // We don't want to point at the following span after DUMMY_SP.
@@ -2039,7 +2059,7 @@ impl<'a> Parser<'a> {
     pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         let (span, msg) = match (&self.token.kind, self.subparser_name) {
             (&token::Eof, Some(origin)) => {
-                let sp = self.sess.source_map().next_point(self.prev_token.span);
+                let sp = self.prev_token.span.shrink_to_hi();
                 (sp, format!("expected expression, found end of {origin}"))
             }
             _ => (
@@ -2232,7 +2252,7 @@ impl<'a> Parser<'a> {
     ///
     /// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest
     /// `foo::<{ bar + 3 }>` and `foo::<{ bar - baz }>`, respectively. We only provide a suggestion
-    /// if we think that that the resulting expression would be well formed.
+    /// if we think that the resulting expression would be well formed.
     pub fn recover_const_arg(
         &mut self,
         start: Span,
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 11301f03e48..0eb633f6416 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -42,8 +42,10 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty
 use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
 use rustc_ast::{ClosureBinder, StmtKind};
 use rustc_ast_pretty::pprust;
-use rustc_errors::IntoDiagnostic;
-use rustc_errors::{Applicability, Diagnostic, PResult};
+use rustc_errors::{
+    Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult,
+    StashKey,
+};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
 use rustc_session::lint::BuiltinLintDiagnostics;
@@ -130,7 +132,7 @@ impl<'a> Parser<'a> {
             Ok(expr) => Ok(expr),
             Err(mut err) => match self.token.ident() {
                 Some((Ident { name: kw::Underscore, .. }, false))
-                    if self.look_ahead(1, |t| t == &token::Comma) =>
+                    if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) =>
                 {
                     // Special-case handling of `foo(_, _, _)`
                     err.emit();
@@ -454,7 +456,7 @@ impl<'a> Parser<'a> {
                 return None;
             }
             (Some(op), _) => (op, self.token.span),
-            (None, Some((Ident { name: sym::and, span }, false))) => {
+            (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => {
                 self.sess.emit_err(InvalidLogicalOperator {
                     span: self.token.span,
                     incorrect: "and".into(),
@@ -462,7 +464,7 @@ impl<'a> Parser<'a> {
                 });
                 (AssocOp::LAnd, span)
             }
-            (None, Some((Ident { name: sym::or, span }, false))) => {
+            (None, Some((Ident { name: sym::or, span }, false))) if self.may_recover() => {
                 self.sess.emit_err(InvalidLogicalOperator {
                     span: self.token.span,
                     incorrect: "or".into(),
@@ -613,7 +615,7 @@ impl<'a> Parser<'a> {
             token::Ident(..) if this.token.is_keyword(kw::Box) => {
                 make_it!(this, attrs, |this, _| this.parse_box_expr(lo))
             }
-            token::Ident(..) if this.is_mistaken_not_ident_negation() => {
+            token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {
                 make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
             }
             _ => return this.parse_dot_or_call_expr(Some(attrs)),
@@ -716,6 +718,10 @@ impl<'a> Parser<'a> {
         let cast_expr = match self.parse_as_cast_ty() {
             Ok(rhs) => mk_expr(self, lhs, rhs),
             Err(type_err) => {
+                if !self.may_recover() {
+                    return Err(type_err);
+                }
+
                 // Rewind to before attempting to parse the type with generics, to recover
                 // from situations like `x as usize < y` in which we first tried to parse
                 // `usize < y` as a type with generic arguments.
@@ -1195,6 +1201,10 @@ impl<'a> Parser<'a> {
         seq: &mut PResult<'a, P<Expr>>,
         snapshot: Option<(SnapshotParser<'a>, ExprKind)>,
     ) -> Option<P<Expr>> {
+        if !self.may_recover() {
+            return None;
+        }
+
         match (seq.as_mut(), snapshot) {
             (Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
                 snapshot.bump(); // `(`
@@ -1358,7 +1368,7 @@ impl<'a> Parser<'a> {
             )
         } else if self.check_inline_const(0) {
             self.parse_const_block(lo.to(self.token.span), false)
-        } else if self.is_do_catch_block() {
+        } else if self.may_recover() && self.is_do_catch_block() {
             self.recover_do_catch()
         } else if self.is_try_block() {
             self.expect_keyword(kw::Try)?;
@@ -1513,11 +1523,11 @@ impl<'a> Parser<'a> {
     /// Parse `'label: $expr`. The label is already parsed.
     fn parse_labeled_expr(
         &mut self,
-        label: Label,
+        label_: Label,
         mut consume_colon: bool,
     ) -> PResult<'a, P<Expr>> {
-        let lo = label.ident.span;
-        let label = Some(label);
+        let lo = label_.ident.span;
+        let label = Some(label_);
         let ate_colon = self.eat(&token::Colon);
         let expr = if self.eat_keyword(kw::While) {
             self.parse_while_expr(label, lo)
@@ -1530,6 +1540,20 @@ impl<'a> Parser<'a> {
         {
             self.parse_block_expr(label, lo, BlockCheckMode::Default)
         } else if !ate_colon
+            && self.may_recover()
+            && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma)
+                || self.token.is_op())
+        {
+            let lit = self.recover_unclosed_char(label_.ident, |self_| {
+                self_.sess.create_err(UnexpectedTokenAfterLabel {
+                    span: self_.token.span,
+                    remove_label: None,
+                    enclose_in_block: None,
+                })
+            });
+            consume_colon = false;
+            Ok(self.mk_expr(lo, ExprKind::Lit(lit)))
+        } else if !ate_colon
             && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
         {
             // We're probably inside of a `Path<'a>` that needs a turbofish
@@ -1603,6 +1627,39 @@ impl<'a> Parser<'a> {
         Ok(expr)
     }
 
+    /// Emit an error when a char is parsed as a lifetime because of a missing quote
+    pub(super) fn recover_unclosed_char(
+        &mut self,
+        lifetime: Ident,
+        err: impl FnOnce(&mut Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>,
+    ) -> ast::Lit {
+        if let Some(mut diag) =
+            self.sess.span_diagnostic.steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar)
+        {
+            diag.span_suggestion_verbose(
+                lifetime.span.shrink_to_hi(),
+                "add `'` to close the char literal",
+                "'",
+                Applicability::MaybeIncorrect,
+            )
+            .emit();
+        } else {
+            err(self)
+                .span_suggestion_verbose(
+                    lifetime.span.shrink_to_hi(),
+                    "add `'` to close the char literal",
+                    "'",
+                    Applicability::MaybeIncorrect,
+                )
+                .emit();
+        }
+        ast::Lit {
+            token_lit: token::Lit::new(token::LitKind::Char, lifetime.name, None),
+            kind: ast::LitKind::Char(lifetime.name.as_str().chars().next().unwrap_or('_')),
+            span: lifetime.span,
+        }
+    }
+
     /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
     fn recover_do_catch(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
@@ -1728,7 +1785,7 @@ impl<'a> Parser<'a> {
     }
 
     pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> {
-        self.parse_opt_lit().ok_or_else(|| {
+        self.parse_opt_lit().ok_or(()).or_else(|()| {
             if let token::Interpolated(inner) = &self.token.kind {
                 let expr = match inner.as_ref() {
                     token::NtExpr(expr) => Some(expr),
@@ -1740,12 +1797,22 @@ impl<'a> Parser<'a> {
                         let mut err = InvalidInterpolatedExpression { span: self.token.span }
                             .into_diagnostic(&self.sess.span_diagnostic);
                         err.downgrade_to_delayed_bug();
-                        return err;
+                        return Err(err);
                     }
                 }
             }
-            let msg = format!("unexpected token: {}", super::token_descr(&self.token));
-            self.struct_span_err(self.token.span, &msg)
+            let token = self.token.clone();
+            let err = |self_: &mut Self| {
+                let msg = format!("unexpected token: {}", super::token_descr(&token));
+                self_.struct_span_err(token.span, &msg)
+            };
+            // On an error path, eagerly consider a lifetime to be an unclosed character lit
+            if self.token.is_lifetime() {
+                let lt = self.expect_lifetime();
+                Ok(self.recover_unclosed_char(lt.ident, err))
+            } else {
+                Err(err(self))
+            }
         })
     }
 
@@ -1941,6 +2008,10 @@ impl<'a> Parser<'a> {
         prev_span: Span,
         open_delim_span: Span,
     ) -> PResult<'a, ()> {
+        if !self.may_recover() {
+            return Ok(());
+        }
+
         if self.token.kind == token::Comma {
             if !self.sess.source_map().is_multiline(prev_span.until(self.token.span)) {
                 return Ok(());
@@ -1981,7 +2052,7 @@ impl<'a> Parser<'a> {
         lo: Span,
         blk_mode: BlockCheckMode,
     ) -> PResult<'a, P<Expr>> {
-        if self.is_array_like_block() {
+        if self.may_recover() && self.is_array_like_block() {
             if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo) {
                 return Ok(arr);
             }
@@ -2051,6 +2122,12 @@ impl<'a> Parser<'a> {
 
         if self.token.kind == TokenKind::Semi
             && matches!(self.token_cursor.frame.delim_sp, Some((Delimiter::Parenthesis, _)))
+            // HACK: This is needed so we can detect whether we're inside a macro,
+            // where regular assumptions about what tokens can follow other tokens
+            // don't necessarily apply.
+            && self.may_recover()
+            // FIXME(Nilstrieb): Remove this check once `may_recover` actually stops recovery
+            && self.subparser_name.is_none()
         {
             // It is likely that the closure body is a block but where the
             // braces have been removed. We will recover and eat the next
@@ -2172,7 +2249,7 @@ impl<'a> Parser<'a> {
                     },
                 ExprKind::Block(_, None) => {
                     self.sess.emit_err(IfExpressionMissingCondition {
-                        if_span: self.sess.source_map().next_point(lo),
+                        if_span: lo.shrink_to_hi(),
                         block_span: self.sess.source_map().start_point(cond_span),
                     });
                     std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi()))
@@ -3080,6 +3157,8 @@ impl<'a> Parser<'a> {
                 && this.token.kind == token::Semi
             {
                 TrailingToken::Semi
+            } else if this.token.kind == token::Gt {
+                TrailingToken::Gt
             } else {
                 // FIXME - pass this through from the place where we know
                 // we need a comma, rather than assuming that `#[attr] expr,`
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index ebcbc75ba32..bda301c52e9 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1601,7 +1601,7 @@ impl<'a> Parser<'a> {
                     self.sess.emit_err(err);
                 } else {
                     if !seen_comma {
-                        let sp = self.sess.source_map().next_point(previous_span);
+                        let sp = previous_span.shrink_to_hi();
                         err.missing_comma = Some(sp);
                     }
                     return Err(err.into_diagnostic(&self.sess.span_diagnostic));
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index b934e087608..2e59c005e31 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -79,6 +79,7 @@ pub enum ForceCollect {
 pub enum TrailingToken {
     None,
     Semi,
+    Gt,
     /// If the trailing token is a comma, then capture it
     /// Otherwise, ignore the trailing token
     MaybeComma,
@@ -103,6 +104,7 @@ macro_rules! maybe_whole {
 macro_rules! maybe_recover_from_interpolated_ty_qpath {
     ($self: expr, $allow_qpath_recovery: expr) => {
         if $allow_qpath_recovery
+                    && $self.may_recover()
                     && $self.look_ahead(1, |t| t == &token::ModSep)
                     && let token::Interpolated(nt) = &$self.token.kind
                     && let token::NtTy(ty) = &**nt
@@ -114,6 +116,12 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
     };
 }
 
+#[derive(Clone, Copy)]
+pub enum Recovery {
+    Allowed,
+    Forbidden,
+}
+
 #[derive(Clone)]
 pub struct Parser<'a> {
     pub sess: &'a ParseSess,
@@ -151,12 +159,15 @@ pub struct Parser<'a> {
     /// This allows us to recover when the user forget to add braces around
     /// multiple statements in the closure body.
     pub current_closure: Option<ClosureSpans>,
+    /// Whether the parser is allowed to do recovery.
+    /// This is disabled when parsing macro arguments, see #103534
+    pub recovery: Recovery,
 }
 
-// This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure
+// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
 // it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Parser<'_>, 328);
+rustc_data_structures::static_assert_size!(Parser<'_>, 336);
 
 /// Stores span information about a closure.
 #[derive(Clone)]
@@ -482,6 +493,7 @@ impl<'a> Parser<'a> {
                 inner_attr_ranges: Default::default(),
             },
             current_closure: None,
+            recovery: Recovery::Allowed,
         };
 
         // Make parser point to the first token.
@@ -490,6 +502,22 @@ impl<'a> Parser<'a> {
         parser
     }
 
+    pub fn forbid_recovery(mut self) -> Self {
+        self.recovery = Recovery::Forbidden;
+        self
+    }
+
+    /// Whether the parser is allowed to recover from broken code.
+    ///
+    /// If this returns false, recovering broken code into valid code (especially if this recovery does lookahead)
+    /// is not allowed. All recovery done by the parser must be gated behind this check.
+    ///
+    /// Technically, this only needs to restrict eager recovery by doing lookahead at more tokens.
+    /// But making the distinction is very subtle, and simply forbidding all recovery is a lot simpler to uphold.
+    fn may_recover(&self) -> bool {
+        matches!(self.recovery, Recovery::Allowed)
+    }
+
     pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
         match self.expect_one_of(&[], &[]) {
             Err(e) => Err(e),
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 56efec422d6..52c11b4e35f 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -402,6 +402,25 @@ impl<'a> Parser<'a> {
             } else {
                 PatKind::Path(qself, path)
             }
+        } else if matches!(self.token.kind, token::Lifetime(_))
+            // In pattern position, we're totally fine with using "next token isn't colon"
+            // as a heuristic. We could probably just always try to recover if it's a lifetime,
+            // because we never have `'a: label {}` in a pattern position anyways, but it does
+            // keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..`
+            && !self.look_ahead(1, |token| matches!(token.kind, token::Colon))
+        {
+            // Recover a `'a` as a `'a'` literal
+            let lt = self.expect_lifetime();
+            let lit = self.recover_unclosed_char(lt.ident, |self_| {
+                let expected = expected.unwrap_or("pattern");
+                let msg =
+                    format!("expected {}, found {}", expected, super::token_descr(&self_.token));
+
+                let mut err = self_.struct_span_err(self_.token.span, &msg);
+                err.span_label(self_.token.span, format!("expected {}", expected));
+                err
+            });
+            PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit)))
         } else {
             // Try to parse everything else as literal with optional minus
             match self.parse_literal_maybe_minus() {
@@ -799,6 +818,7 @@ impl<'a> Parser<'a> {
                 || t.kind == token::Dot // e.g. `.5` for recovery;
                 || t.can_begin_literal_maybe_minus() // e.g. `42`.
                 || t.is_whole_expr()
+                || t.is_lifetime() // recover `'a` instead of `'a'`
             })
     }
 
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index a61e77b7c3b..12753c6785c 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -553,39 +553,46 @@ impl<'a> Parser<'a> {
         match stmt.kind {
             // Expression without semicolon.
             StmtKind::Expr(ref mut expr)
-                if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) =>
-            {
+                if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => {
                 // Just check for errors and recover; do not eat semicolon yet.
-                if let Err(mut e) =
-                    self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)])
-                {
-                    if let TokenKind::DocComment(..) = self.token.kind {
-                        if let Ok(snippet) = self.span_to_snippet(self.token.span) {
-                            let sp = self.token.span;
-                            let marker = &snippet[..3];
-                            let (comment_marker, doc_comment_marker) = marker.split_at(2);
-
-                            e.span_suggestion(
-                                sp.with_hi(sp.lo() + BytePos(marker.len() as u32)),
-                                &format!(
-                                    "add a space before `{}` to use a regular comment",
-                                    doc_comment_marker,
-                                ),
-                                format!("{} {}", comment_marker, doc_comment_marker),
-                                Applicability::MaybeIncorrect,
-                            );
+                // `expect_one_of` returns PResult<'a, bool /* recovered */>
+                let replace_with_err =
+                    match self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]) {
+                    // Recover from parser, skip type error to avoid extra errors.
+                    Ok(true) => true,
+                    Err(mut e) => {
+                        if let TokenKind::DocComment(..) = self.token.kind &&
+                            let Ok(snippet) = self.span_to_snippet(self.token.span) {
+                                let sp = self.token.span;
+                                let marker = &snippet[..3];
+                                let (comment_marker, doc_comment_marker) = marker.split_at(2);
+
+                                e.span_suggestion(
+                                    sp.with_hi(sp.lo() + BytePos(marker.len() as u32)),
+                                    &format!(
+                                        "add a space before `{}` to use a regular comment",
+                                        doc_comment_marker,
+                                    ),
+                                    format!("{} {}", comment_marker, doc_comment_marker),
+                                    Applicability::MaybeIncorrect,
+                                );
                         }
-                    }
-                    if let Err(mut e) =
-                        self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
-                    {
-                        if recover.no() {
-                            return Err(e);
+
+                        if let Err(mut e) =
+                            self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
+                        {
+                            if recover.no() {
+                                return Err(e);
+                            }
+                            e.emit();
+                            self.recover_stmt();
                         }
-                        e.emit();
-                        self.recover_stmt();
+                        true
                     }
-                    // Don't complain about type errors in body tail after parse error (#57383).
+                    _ => false
+                };
+                if replace_with_err {
+                    // We already emitted an error, so don't emit another type error
                     let sp = expr.span.to(self.prev_token.span);
                     *expr = self.mk_expr_err(sp);
                 }
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index df22d79f82e..1394993abad 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -740,20 +740,40 @@ impl<'a> Parser<'a> {
         word
     }
 
-    /// Optionally parses an integer at the current position. This doesn't deal
-    /// with overflow at all, it's just accumulating digits.
     fn integer(&mut self) -> Option<usize> {
-        let mut cur = 0;
+        let mut cur: usize = 0;
         let mut found = false;
+        let mut overflow = false;
+        let start = self.current_pos();
         while let Some(&(_, c)) = self.cur.peek() {
             if let Some(i) = c.to_digit(10) {
-                cur = cur * 10 + i as usize;
+                let (tmp, mul_overflow) = cur.overflowing_mul(10);
+                let (tmp, add_overflow) = tmp.overflowing_add(i as usize);
+                if mul_overflow || add_overflow {
+                    overflow = true;
+                }
+                cur = tmp;
                 found = true;
                 self.cur.next();
             } else {
                 break;
             }
         }
+
+        if overflow {
+            let end = self.current_pos();
+            let overflowed_int = &self.input[start..end];
+            self.err(
+                format!(
+                    "integer `{}` does not fit into the type `usize` whose range is `0..={}`",
+                    overflowed_int,
+                    usize::MAX
+                ),
+                "integer out of range for `usize`",
+                self.span(start, end),
+            );
+        }
+
         if found { Some(cur) } else { None }
     }
 
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index 2f8c229c68f..3f9cb149b53 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -58,6 +58,21 @@ fn invalid06() {
 }
 
 #[test]
+fn invalid_position() {
+    musterr("{18446744073709551616}");
+}
+
+#[test]
+fn invalid_width() {
+    musterr("{:18446744073709551616}");
+}
+
+#[test]
+fn invalid_precision() {
+    musterr("{:.18446744073709551616}");
+}
+
+#[test]
 fn format_nothing() {
     same(
         "{}",
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 73fb89bbc38..27a57adf964 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -268,7 +268,7 @@ impl CheckAttrVisitor<'_> {
             }
             // FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with
             // just a lint, because we previously erroneously allowed it and some crates used it
-            // accidentally, to to be compatible with crates depending on them, we can't throw an
+            // accidentally, to be compatible with crates depending on them, we can't throw an
             // error here.
             Target::AssocConst => {
                 self.tcx.emit_spanned_lint(
@@ -376,7 +376,7 @@ impl CheckAttrVisitor<'_> {
             | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[allow_internal_unstable]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked");
@@ -456,7 +456,7 @@ impl CheckAttrVisitor<'_> {
             Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true,
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[track_caller]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 for attr in attrs {
@@ -485,7 +485,7 @@ impl CheckAttrVisitor<'_> {
             Target::Struct | Target::Enum | Target::Variant => true,
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[non_exhaustive]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive");
@@ -507,7 +507,7 @@ impl CheckAttrVisitor<'_> {
             Target::Trait => true,
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[marker]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker");
@@ -566,7 +566,7 @@ impl CheckAttrVisitor<'_> {
             }
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[target_feature]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
@@ -822,8 +822,8 @@ impl CheckAttrVisitor<'_> {
             if let Some((prev_inline, prev_span)) = *specified_inline {
                 if do_inline != prev_inline {
                     let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]);
-                    spans.push_span_label(prev_span, fluent::passes::doc_inline_conflict_first);
-                    spans.push_span_label(meta.span(), fluent::passes::doc_inline_conflict_second);
+                    spans.push_span_label(prev_span, fluent::passes_doc_inline_conflict_first);
+                    spans.push_span_label(meta.span(), fluent::passes_doc_inline_conflict_second);
                     self.tcx.sess.emit_err(errors::DocKeywordConflict { spans });
                     return false;
                 }
@@ -873,7 +873,7 @@ impl CheckAttrVisitor<'_> {
                 INVALID_DOC_ATTRIBUTES,
                 hir_id,
                 meta.span(),
-                fluent::passes::attr_crate_level,
+                fluent::passes_attr_crate_level,
                 |err| {
                     if attr.style == AttrStyle::Outer
                         && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID
@@ -882,15 +882,15 @@ impl CheckAttrVisitor<'_> {
                             src.insert(1, '!');
                             err.span_suggestion_verbose(
                                 attr.span,
-                                fluent::passes::suggestion,
+                                fluent::suggestion,
                                 src,
                                 Applicability::MaybeIncorrect,
                             );
                         } else {
-                            err.span_help(attr.span, fluent::passes::help);
+                            err.span_help(attr.span, fluent::help);
                         }
                     }
-                    err.note(fluent::passes::note);
+                    err.note(fluent::note);
                     err
                 },
             );
@@ -934,6 +934,22 @@ impl CheckAttrVisitor<'_> {
         is_valid
     }
 
+    /// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes.
+    /// Returns `true` if valid.
+    fn check_doc_cfg_hide(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
+        if meta.meta_item_list().is_some() {
+            true
+        } else {
+            self.tcx.emit_spanned_lint(
+                INVALID_DOC_ATTRIBUTES,
+                hir_id,
+                meta.span(),
+                errors::DocCfgHideTakesList,
+            );
+            false
+        }
+    }
+
     /// Runs various checks on `#[doc]` attributes. Returns `true` if valid.
     ///
     /// `specified_inline` should be initialized to `None` and kept for the scope
@@ -987,6 +1003,13 @@ impl CheckAttrVisitor<'_> {
                             is_valid = false;
                         }
 
+                        sym::cfg_hide
+                            if !self.check_attr_crate_level(attr, meta, hir_id)
+                                || !self.check_doc_cfg_hide(meta, hir_id) =>
+                        {
+                            is_valid = false;
+                        }
+
                         sym::inline | sym::no_inline
                             if !self.check_doc_inline(
                                 attr,
@@ -1205,7 +1228,7 @@ impl CheckAttrVisitor<'_> {
             Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[cold]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "cold");
@@ -1247,7 +1270,7 @@ impl CheckAttrVisitor<'_> {
             Target::ForeignFn | Target::ForeignStatic => {}
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[link_name]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name");
@@ -1281,7 +1304,7 @@ impl CheckAttrVisitor<'_> {
             Target::ExternCrate => true,
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[no_link]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link");
@@ -1311,7 +1334,7 @@ impl CheckAttrVisitor<'_> {
             Target::Method(..) if self.is_impl_item(hir_id) => true,
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[export_name]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name");
@@ -1503,7 +1526,7 @@ impl CheckAttrVisitor<'_> {
             Target::Static | Target::Fn | Target::Method(..) => {}
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[link_section]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section");
@@ -1528,7 +1551,7 @@ impl CheckAttrVisitor<'_> {
             Target::Method(..) if self.is_impl_item(hir_id) => {}
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[no_mangle]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle");
@@ -1782,7 +1805,7 @@ impl CheckAttrVisitor<'_> {
             Target::MacroDef => true,
             // FIXME(#80564): We permit struct fields and match arms to have an
             // `#[allow_internal_unstable]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm => {
                 self.inline_attr_str_error_without_macro_def(
@@ -1877,7 +1900,7 @@ impl CheckAttrVisitor<'_> {
             }
             // FIXME(#80564): We permit struct fields and match arms to have an
             // `#[allow_internal_unstable]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable");
@@ -2039,7 +2062,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
         // so this lets us continue to run them while maintaining backwards compatibility.
         // In the long run, the checks should be harmonized.
         if let ItemKind::Macro(ref macro_def, _) = item.kind {
-            let def_id = item.def_id.to_def_id();
+            let def_id = item.owner_id.to_def_id();
             if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
                 check_non_exported_macro_for_invalid_attrs(self.tcx, item);
             }
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 6a97ad3fe86..b779edbc30f 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -11,7 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Node, PatKind, TyKind};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::middle::privacy::AccessLevel;
+use rustc_middle::middle::privacy::Level;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::lint;
@@ -280,8 +280,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
     }
 
     fn visit_node(&mut self, node: Node<'tcx>) {
-        if let Node::ImplItem(hir::ImplItem { def_id, .. }) = node
-            && self.should_ignore_item(def_id.to_def_id())
+        if let Node::ImplItem(hir::ImplItem { owner_id, .. }) = node
+            && self.should_ignore_item(owner_id.to_def_id())
         {
             return;
         }
@@ -293,7 +293,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         match node {
             Node::Item(item) => match item.kind {
                 hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
-                    let def = self.tcx.adt_def(item.def_id);
+                    let def = self.tcx.adt_def(item.owner_id);
                     self.repr_has_repr_c = def.repr().c();
                     self.repr_has_repr_simd = def.repr().simd();
 
@@ -306,7 +306,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                 intravisit::walk_trait_item(self, trait_item);
             }
             Node::ImplItem(impl_item) => {
-                let item = self.tcx.local_parent(impl_item.def_id.def_id);
+                let item = self.tcx.local_parent(impl_item.owner_id.def_id);
                 if self.tcx.impl_trait_ref(item).is_none() {
                     //// If it's a type whose items are live, then it's live, too.
                     //// This is done to handle the case where, for example, the static
@@ -470,11 +470,6 @@ fn has_allow_dead_code_or_lang_attr_helper(
         return true;
     }
 
-    // (To be) stable attribute for #[lang = "oom"]
-    if tcx.sess.contains_name(attrs, sym::alloc_error_handler) {
-        return true;
-    }
-
     let def_id = tcx.hir().local_def_id(id);
     if tcx.def_kind(def_id).has_codegen_attrs() {
         let cg_attrs = tcx.codegen_fn_attrs(def_id);
@@ -517,10 +512,10 @@ fn check_item<'tcx>(
 ) {
     let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id());
     if allow_dead_code {
-        worklist.push(id.def_id.def_id);
+        worklist.push(id.owner_id.def_id);
     }
 
-    match tcx.def_kind(id.def_id) {
+    match tcx.def_kind(id.owner_id) {
         DefKind::Enum => {
             let item = tcx.hir().item(id);
             if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
@@ -540,15 +535,15 @@ fn check_item<'tcx>(
             }
         }
         DefKind::Impl => {
-            let of_trait = tcx.impl_trait_ref(id.def_id);
+            let of_trait = tcx.impl_trait_ref(id.owner_id);
 
             if of_trait.is_some() {
-                worklist.push(id.def_id.def_id);
+                worklist.push(id.owner_id.def_id);
             }
 
             // get DefIds from another query
             let local_def_ids = tcx
-                .associated_item_def_ids(id.def_id)
+                .associated_item_def_ids(id.owner_id)
                 .iter()
                 .filter_map(|def_id| def_id.as_local());
 
@@ -566,12 +561,12 @@ fn check_item<'tcx>(
             if let hir::ItemKind::Struct(ref variant_data, _) = item.kind
                 && let Some(ctor_hir_id) = variant_data.ctor_hir_id()
             {
-                struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id.def_id);
+                struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.owner_id.def_id);
             }
         }
         DefKind::GlobalAsm => {
             // global_asm! is always live.
-            worklist.push(id.def_id.def_id);
+            worklist.push(id.owner_id.def_id);
         }
         _ => {}
     }
@@ -579,12 +574,12 @@ fn check_item<'tcx>(
 
 fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, worklist: &mut Vec<LocalDefId>, id: hir::TraitItemId) {
     use hir::TraitItemKind::{Const, Fn};
-    if matches!(tcx.def_kind(id.def_id), DefKind::AssocConst | DefKind::AssocFn) {
+    if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) {
         let trait_item = tcx.hir().trait_item(id);
         if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
             && has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id())
         {
-            worklist.push(trait_item.def_id.def_id);
+            worklist.push(trait_item.owner_id.def_id);
         }
     }
 }
@@ -594,23 +589,23 @@ fn check_foreign_item<'tcx>(
     worklist: &mut Vec<LocalDefId>,
     id: hir::ForeignItemId,
 ) {
-    if matches!(tcx.def_kind(id.def_id), DefKind::Static(_) | DefKind::Fn)
+    if matches!(tcx.def_kind(id.owner_id), DefKind::Static(_) | DefKind::Fn)
         && has_allow_dead_code_or_lang_attr(tcx, id.hir_id())
     {
-        worklist.push(id.def_id.def_id);
+        worklist.push(id.owner_id.def_id);
     }
 }
 
 fn create_and_seed_worklist<'tcx>(
     tcx: TyCtxt<'tcx>,
 ) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
-    let access_levels = &tcx.privacy_access_levels(());
+    let effective_visibilities = &tcx.effective_visibilities(());
     // see `MarkSymbolVisitor::struct_constructors`
     let mut struct_constructors = Default::default();
-    let mut worklist = access_levels
+    let mut worklist = effective_visibilities
         .iter()
         .filter_map(|(&id, effective_vis)| {
-            effective_vis.is_public_at_level(AccessLevel::Reachable).then_some(id)
+            effective_vis.is_public_at_level(Level::Reachable).then_some(id)
         })
         // Seed entry point
         .chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
@@ -861,19 +856,19 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
     let module_items = tcx.hir_module_items(module);
 
     for item in module_items.items() {
-        if !live_symbols.contains(&item.def_id.def_id) {
-            let parent = tcx.local_parent(item.def_id.def_id);
+        if !live_symbols.contains(&item.owner_id.def_id) {
+            let parent = tcx.local_parent(item.owner_id.def_id);
             if parent != module && !live_symbols.contains(&parent) {
                 // We already have diagnosed something.
                 continue;
             }
-            visitor.check_definition(item.def_id.def_id);
+            visitor.check_definition(item.owner_id.def_id);
             continue;
         }
 
-        let def_kind = tcx.def_kind(item.def_id);
+        let def_kind = tcx.def_kind(item.owner_id);
         if let DefKind::Struct | DefKind::Union | DefKind::Enum = def_kind {
-            let adt = tcx.adt_def(item.def_id);
+            let adt = tcx.adt_def(item.owner_id);
             let mut dead_variants = Vec::new();
 
             for variant in adt.variants() {
@@ -917,7 +912,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
             }
 
             visitor.warn_dead_fields_and_variants(
-                item.def_id.def_id,
+                item.owner_id.def_id,
                 "constructed",
                 dead_variants,
                 false,
@@ -926,11 +921,11 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
     }
 
     for impl_item in module_items.impl_items() {
-        visitor.check_definition(impl_item.def_id.def_id);
+        visitor.check_definition(impl_item.owner_id.def_id);
     }
 
     for foreign_item in module_items.foreign_items() {
-        visitor.check_definition(foreign_item.def_id.def_id);
+        visitor.check_definition(foreign_item.owner_id.def_id);
     }
 
     // We do not warn trait items.
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index 3f991cf6572..a72056e00b1 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -73,19 +73,19 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems
     let crate_items = tcx.hir_crate_items(());
 
     for id in crate_items.items() {
-        observe_item(tcx, &mut diagnostic_items, id.def_id.def_id);
+        observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
     }
 
     for id in crate_items.trait_items() {
-        observe_item(tcx, &mut diagnostic_items, id.def_id.def_id);
+        observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
     }
 
     for id in crate_items.impl_items() {
-        observe_item(tcx, &mut diagnostic_items, id.def_id.def_id);
+        observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
     }
 
     for id in crate_items.foreign_items() {
-        observe_item(tcx, &mut diagnostic_items, id.def_id.def_id);
+        observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
     }
 
     diagnostic_items
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 38a259ca884..5885f45ae45 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -62,7 +62,7 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry
     } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
         EntryPointType::RustcMainAttr
     } else {
-        if let Some(name) = ctxt.tcx.opt_item_name(id.def_id.to_def_id())
+        if let Some(name) = ctxt.tcx.opt_item_name(id.owner_id.to_def_id())
             && name == sym::main {
             if at_root {
                 // This is a top-level function so can be `main`.
@@ -82,7 +82,7 @@ fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Opti
 }
 
 fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
-    let at_root = ctxt.tcx.opt_local_parent(id.def_id.def_id) == Some(CRATE_DEF_ID);
+    let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID);
 
     match entry_point_type(ctxt, id, at_root) {
         EntryPointType::None => {
@@ -90,7 +90,7 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
                 ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
             }
         }
-        _ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
+        _ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => {
             for attr in [sym::start, sym::rustc_main] {
                 if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
                     ctxt.tcx.sess.emit_err(AttrOnlyInFunctions { span, attr });
@@ -102,16 +102,16 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
             if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
                 ctxt.tcx.sess.emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe });
             }
-            ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
+            ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id));
         }
         EntryPointType::RustcMainAttr => {
             if ctxt.attr_main_fn.is_none() {
-                ctxt.attr_main_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
+                ctxt.attr_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
             } else {
                 ctxt.tcx.sess.emit_err(MultipleRustcMain {
-                    span: ctxt.tcx.def_span(id.def_id.to_def_id()),
+                    span: ctxt.tcx.def_span(id.owner_id.to_def_id()),
                     first: ctxt.attr_main_fn.unwrap().1,
-                    additional: ctxt.tcx.def_span(id.def_id.to_def_id()),
+                    additional: ctxt.tcx.def_span(id.owner_id.to_def_id()),
                 });
             }
         }
@@ -120,11 +120,11 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
                 ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
             }
             if ctxt.start_fn.is_none() {
-                ctxt.start_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
+                ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
             } else {
                 ctxt.tcx.sess.emit_err(MultipleStartFunctions {
-                    span: ctxt.tcx.def_span(id.def_id),
-                    labeled: ctxt.tcx.def_span(id.def_id.to_def_id()),
+                    span: ctxt.tcx.def_span(id.owner_id),
+                    labeled: ctxt.tcx.def_span(id.owner_id.to_def_id()),
                     previous: ctxt.start_fn.unwrap().1,
                 });
             }
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 1cc81a9ab98..fb883ae2ed0 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -13,37 +13,37 @@ use rustc_span::{Span, Symbol, DUMMY_SP};
 use crate::lang_items::Duplicate;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::outer_crate_level_attr)]
+#[diag(passes_outer_crate_level_attr)]
 pub struct OuterCrateLevelAttr;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::inner_crate_level_attr)]
+#[diag(passes_inner_crate_level_attr)]
 pub struct InnerCrateLevelAttr;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::ignored_attr_with_macro)]
+#[diag(passes_ignored_attr_with_macro)]
 pub struct IgnoredAttrWithMacro<'a> {
     pub sym: &'a str,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::ignored_attr)]
+#[diag(passes_ignored_attr)]
 pub struct IgnoredAttr<'a> {
     pub sym: &'a str,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::inline_ignored_function_prototype)]
+#[diag(passes_inline_ignored_function_prototype)]
 pub struct IgnoredInlineAttrFnProto;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::inline_ignored_constants)]
+#[diag(passes_inline_ignored_constants)]
 #[warning]
 #[note]
 pub struct IgnoredInlineAttrConstants;
 
 #[derive(Diagnostic)]
-#[diag(passes::inline_not_fn_or_closure, code = "E0518")]
+#[diag(passes_inline_not_fn_or_closure, code = "E0518")]
 pub struct InlineNotFnOrClosure {
     #[primary_span]
     pub attr_span: Span,
@@ -52,19 +52,19 @@ pub struct InlineNotFnOrClosure {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::no_coverage_ignored_function_prototype)]
+#[diag(passes_no_coverage_ignored_function_prototype)]
 pub struct IgnoredNoCoverageFnProto;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::no_coverage_propagate)]
+#[diag(passes_no_coverage_propagate)]
 pub struct IgnoredNoCoveragePropagate;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::no_coverage_fn_defn)]
+#[diag(passes_no_coverage_fn_defn)]
 pub struct IgnoredNoCoverageFnDefn;
 
 #[derive(Diagnostic)]
-#[diag(passes::no_coverage_not_coverable, code = "E0788")]
+#[diag(passes_no_coverage_not_coverable, code = "E0788")]
 pub struct IgnoredNoCoverageNotCoverable {
     #[primary_span]
     pub attr_span: Span,
@@ -73,7 +73,7 @@ pub struct IgnoredNoCoverageNotCoverable {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::should_be_applied_to_fn)]
+#[diag(passes_should_be_applied_to_fn)]
 pub struct AttrShouldBeAppliedToFn {
     #[primary_span]
     pub attr_span: Span,
@@ -82,14 +82,14 @@ pub struct AttrShouldBeAppliedToFn {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::naked_tracked_caller, code = "E0736")]
+#[diag(passes_naked_tracked_caller, code = "E0736")]
 pub struct NakedTrackedCaller {
     #[primary_span]
     pub attr_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::should_be_applied_to_fn, code = "E0739")]
+#[diag(passes_should_be_applied_to_fn, code = "E0739")]
 pub struct TrackedCallerWrongLocation {
     #[primary_span]
     pub attr_span: Span,
@@ -98,7 +98,7 @@ pub struct TrackedCallerWrongLocation {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::should_be_applied_to_struct_enum, code = "E0701")]
+#[diag(passes_should_be_applied_to_struct_enum, code = "E0701")]
 pub struct NonExhaustiveWrongLocation {
     #[primary_span]
     pub attr_span: Span,
@@ -107,7 +107,7 @@ pub struct NonExhaustiveWrongLocation {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::should_be_applied_to_trait)]
+#[diag(passes_should_be_applied_to_trait)]
 pub struct AttrShouldBeAppliedToTrait {
     #[primary_span]
     pub attr_span: Span,
@@ -116,11 +116,11 @@ pub struct AttrShouldBeAppliedToTrait {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::target_feature_on_statement)]
+#[diag(passes_target_feature_on_statement)]
 pub struct TargetFeatureOnStatement;
 
 #[derive(Diagnostic)]
-#[diag(passes::should_be_applied_to_static)]
+#[diag(passes_should_be_applied_to_static)]
 pub struct AttrShouldBeAppliedToStatic {
     #[primary_span]
     pub attr_span: Span,
@@ -129,7 +129,7 @@ pub struct AttrShouldBeAppliedToStatic {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_expect_str)]
+#[diag(passes_doc_expect_str)]
 pub struct DocExpectStr<'a> {
     #[primary_span]
     pub attr_span: Span,
@@ -137,7 +137,7 @@ pub struct DocExpectStr<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_empty)]
+#[diag(passes_doc_alias_empty)]
 pub struct DocAliasEmpty<'a> {
     #[primary_span]
     pub span: Span,
@@ -145,7 +145,7 @@ pub struct DocAliasEmpty<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_bad_char)]
+#[diag(passes_doc_alias_bad_char)]
 pub struct DocAliasBadChar<'a> {
     #[primary_span]
     pub span: Span,
@@ -154,7 +154,7 @@ pub struct DocAliasBadChar<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_start_end)]
+#[diag(passes_doc_alias_start_end)]
 pub struct DocAliasStartEnd<'a> {
     #[primary_span]
     pub span: Span,
@@ -162,7 +162,7 @@ pub struct DocAliasStartEnd<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_bad_location)]
+#[diag(passes_doc_alias_bad_location)]
 pub struct DocAliasBadLocation<'a> {
     #[primary_span]
     pub span: Span,
@@ -171,7 +171,7 @@ pub struct DocAliasBadLocation<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_not_an_alias)]
+#[diag(passes_doc_alias_not_an_alias)]
 pub struct DocAliasNotAnAlias<'a> {
     #[primary_span]
     pub span: Span,
@@ -179,42 +179,42 @@ pub struct DocAliasNotAnAlias<'a> {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_alias_duplicated)]
+#[diag(passes_doc_alias_duplicated)]
 pub struct DocAliasDuplicated {
     #[label]
     pub first_defn: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_not_string_literal)]
+#[diag(passes_doc_alias_not_string_literal)]
 pub struct DocAliasNotStringLiteral {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_malformed)]
+#[diag(passes_doc_alias_malformed)]
 pub struct DocAliasMalformed {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_keyword_empty_mod)]
+#[diag(passes_doc_keyword_empty_mod)]
 pub struct DocKeywordEmptyMod {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_keyword_not_mod)]
+#[diag(passes_doc_keyword_not_mod)]
 pub struct DocKeywordNotMod {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_keyword_invalid_ident)]
+#[diag(passes_doc_keyword_invalid_ident)]
 pub struct DocKeywordInvalidIdent {
     #[primary_span]
     pub span: Span,
@@ -222,21 +222,21 @@ pub struct DocKeywordInvalidIdent {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_fake_variadic_not_valid)]
+#[diag(passes_doc_fake_variadic_not_valid)]
 pub struct DocFakeVariadicNotValid {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_keyword_only_impl)]
+#[diag(passes_doc_keyword_only_impl)]
 pub struct DocKeywordOnlyImpl {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_inline_conflict)]
+#[diag(passes_doc_inline_conflict)]
 #[help]
 pub struct DocKeywordConflict {
     #[primary_span]
@@ -244,17 +244,17 @@ pub struct DocKeywordConflict {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_inline_only_use)]
+#[diag(passes_doc_inline_only_use)]
 #[note]
 pub struct DocInlineOnlyUse {
     #[label]
     pub attr_span: Span,
-    #[label(passes::not_a_use_item_label)]
+    #[label(not_a_use_item_label)]
     pub item_span: Option<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_attr_not_crate_level)]
+#[diag(passes_doc_attr_not_crate_level)]
 pub struct DocAttrNotCrateLevel<'a> {
     #[primary_span]
     pub span: Span,
@@ -262,37 +262,41 @@ pub struct DocAttrNotCrateLevel<'a> {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_test_unknown)]
+#[diag(passes_doc_test_unknown)]
 pub struct DocTestUnknown {
     pub path: String,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_test_takes_list)]
+#[diag(passes_doc_test_takes_list)]
 pub struct DocTestTakesList;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_primitive)]
+#[diag(passes_doc_cfg_hide_takes_list)]
+pub struct DocCfgHideTakesList;
+
+#[derive(LintDiagnostic)]
+#[diag(passes_doc_primitive)]
 pub struct DocPrimitive;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_test_unknown_any)]
+#[diag(passes_doc_test_unknown_any)]
 pub struct DocTestUnknownAny {
     pub path: String,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_test_unknown_spotlight)]
+#[diag(passes_doc_test_unknown_spotlight)]
 #[note]
-#[note(passes::no_op_note)]
+#[note(no_op_note)]
 pub struct DocTestUnknownSpotlight {
     pub path: String,
-    #[suggestion_short(applicability = "machine-applicable", code = "notable_trait")]
+    #[suggestion(style = "short", applicability = "machine-applicable", code = "notable_trait")]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_test_unknown_include)]
+#[diag(passes_doc_test_unknown_include)]
 pub struct DocTestUnknownInclude {
     pub path: String,
     pub value: String,
@@ -302,11 +306,11 @@ pub struct DocTestUnknownInclude {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_invalid)]
+#[diag(passes_doc_invalid)]
 pub struct DocInvalid;
 
 #[derive(Diagnostic)]
-#[diag(passes::pass_by_value)]
+#[diag(passes_pass_by_value)]
 pub struct PassByValue {
     #[primary_span]
     pub attr_span: Span,
@@ -315,7 +319,7 @@ pub struct PassByValue {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::allow_incoherent_impl)]
+#[diag(passes_allow_incoherent_impl)]
 pub struct AllowIncoherentImpl {
     #[primary_span]
     pub attr_span: Span,
@@ -324,7 +328,7 @@ pub struct AllowIncoherentImpl {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::has_incoherent_inherent_impl)]
+#[diag(passes_has_incoherent_inherent_impl)]
 pub struct HasIncoherentInherentImpl {
     #[primary_span]
     pub attr_span: Span,
@@ -333,21 +337,21 @@ pub struct HasIncoherentInherentImpl {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::must_use_async)]
+#[diag(passes_must_use_async)]
 pub struct MustUseAsync {
     #[label]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::must_use_no_effect)]
+#[diag(passes_must_use_no_effect)]
 pub struct MustUseNoEffect {
     pub article: &'static str,
     pub target: rustc_hir::Target,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::must_not_suspend)]
+#[diag(passes_must_not_suspend)]
 pub struct MustNotSuspend {
     #[primary_span]
     pub attr_span: Span,
@@ -356,7 +360,7 @@ pub struct MustNotSuspend {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::cold)]
+#[diag(passes_cold)]
 #[warning]
 pub struct Cold {
     #[label]
@@ -364,7 +368,7 @@ pub struct Cold {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::link)]
+#[diag(passes_link)]
 #[warning]
 pub struct Link {
     #[label]
@@ -372,7 +376,7 @@ pub struct Link {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::link_name)]
+#[diag(passes_link_name)]
 #[warning]
 pub struct LinkName<'a> {
     #[help]
@@ -383,7 +387,7 @@ pub struct LinkName<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::no_link)]
+#[diag(passes_no_link)]
 pub struct NoLink {
     #[primary_span]
     pub attr_span: Span,
@@ -392,7 +396,7 @@ pub struct NoLink {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::export_name)]
+#[diag(passes_export_name)]
 pub struct ExportName {
     #[primary_span]
     pub attr_span: Span,
@@ -401,7 +405,7 @@ pub struct ExportName {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_layout_scalar_valid_range_not_struct)]
+#[diag(passes_rustc_layout_scalar_valid_range_not_struct)]
 pub struct RustcLayoutScalarValidRangeNotStruct {
     #[primary_span]
     pub attr_span: Span,
@@ -410,14 +414,14 @@ pub struct RustcLayoutScalarValidRangeNotStruct {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_layout_scalar_valid_range_arg)]
+#[diag(passes_rustc_layout_scalar_valid_range_arg)]
 pub struct RustcLayoutScalarValidRangeArg {
     #[primary_span]
     pub attr_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_legacy_const_generics_only)]
+#[diag(passes_rustc_legacy_const_generics_only)]
 pub struct RustcLegacyConstGenericsOnly {
     #[primary_span]
     pub attr_span: Span,
@@ -426,7 +430,7 @@ pub struct RustcLegacyConstGenericsOnly {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_legacy_const_generics_index)]
+#[diag(passes_rustc_legacy_const_generics_index)]
 pub struct RustcLegacyConstGenericsIndex {
     #[primary_span]
     pub attr_span: Span,
@@ -435,7 +439,7 @@ pub struct RustcLegacyConstGenericsIndex {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_legacy_const_generics_index_exceed)]
+#[diag(passes_rustc_legacy_const_generics_index_exceed)]
 pub struct RustcLegacyConstGenericsIndexExceed {
     #[primary_span]
     #[label]
@@ -444,21 +448,21 @@ pub struct RustcLegacyConstGenericsIndexExceed {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_legacy_const_generics_index_negative)]
+#[diag(passes_rustc_legacy_const_generics_index_negative)]
 pub struct RustcLegacyConstGenericsIndexNegative {
     #[primary_span]
     pub invalid_args: Vec<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_dirty_clean)]
+#[diag(passes_rustc_dirty_clean)]
 pub struct RustcDirtyClean {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::link_section)]
+#[diag(passes_link_section)]
 #[warning]
 pub struct LinkSection {
     #[label]
@@ -466,7 +470,7 @@ pub struct LinkSection {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::no_mangle_foreign)]
+#[diag(passes_no_mangle_foreign)]
 #[warning]
 #[note]
 pub struct NoMangleForeign {
@@ -478,7 +482,7 @@ pub struct NoMangleForeign {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::no_mangle)]
+#[diag(passes_no_mangle)]
 #[warning]
 pub struct NoMangle {
     #[label]
@@ -486,32 +490,32 @@ pub struct NoMangle {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::repr_ident, code = "E0565")]
+#[diag(passes_repr_ident, code = "E0565")]
 pub struct ReprIdent {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::repr_conflicting, code = "E0566")]
+#[diag(passes_repr_conflicting, code = "E0566")]
 pub struct ReprConflicting;
 
 #[derive(Diagnostic)]
-#[diag(passes::used_static)]
+#[diag(passes_used_static)]
 pub struct UsedStatic {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::used_compiler_linker)]
+#[diag(passes_used_compiler_linker)]
 pub struct UsedCompilerLinker {
     #[primary_span]
     pub spans: Vec<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::allow_internal_unstable)]
+#[diag(passes_allow_internal_unstable)]
 pub struct AllowInternalUnstable {
     #[primary_span]
     pub attr_span: Span,
@@ -520,24 +524,24 @@ pub struct AllowInternalUnstable {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::debug_visualizer_placement)]
+#[diag(passes_debug_visualizer_placement)]
 pub struct DebugVisualizerPlacement {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::debug_visualizer_invalid)]
-#[note(passes::note_1)]
-#[note(passes::note_2)]
-#[note(passes::note_3)]
+#[diag(passes_debug_visualizer_invalid)]
+#[note(note_1)]
+#[note(note_2)]
+#[note(note_3)]
 pub struct DebugVisualizerInvalid {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::debug_visualizer_unreadable)]
+#[diag(passes_debug_visualizer_unreadable)]
 pub struct DebugVisualizerUnreadable<'a> {
     #[primary_span]
     pub span: Span,
@@ -546,7 +550,7 @@ pub struct DebugVisualizerUnreadable<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_allow_const_fn_unstable)]
+#[diag(passes_rustc_allow_const_fn_unstable)]
 pub struct RustcAllowConstFnUnstable {
     #[primary_span]
     pub attr_span: Span,
@@ -555,7 +559,7 @@ pub struct RustcAllowConstFnUnstable {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_std_internal_symbol)]
+#[diag(passes_rustc_std_internal_symbol)]
 pub struct RustcStdInternalSymbol {
     #[primary_span]
     pub attr_span: Span,
@@ -564,56 +568,56 @@ pub struct RustcStdInternalSymbol {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::const_trait)]
+#[diag(passes_const_trait)]
 pub struct ConstTrait {
     #[primary_span]
     pub attr_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::link_ordinal)]
+#[diag(passes_link_ordinal)]
 pub struct LinkOrdinal {
     #[primary_span]
     pub attr_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::stability_promotable)]
+#[diag(passes_stability_promotable)]
 pub struct StabilityPromotable {
     #[primary_span]
     pub attr_span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::deprecated)]
+#[diag(passes_deprecated)]
 pub struct Deprecated;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::macro_use)]
+#[diag(passes_macro_use)]
 pub struct MacroUse {
     pub name: Symbol,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::macro_export)]
+#[diag(passes_macro_export)]
 pub struct MacroExport;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::plugin_registrar)]
+#[diag(passes_plugin_registrar)]
 pub struct PluginRegistrar;
 
 #[derive(Subdiagnostic)]
 pub enum UnusedNote {
-    #[note(passes::unused_empty_lints_note)]
+    #[note(passes_unused_empty_lints_note)]
     EmptyList { name: Symbol },
-    #[note(passes::unused_no_lints_note)]
+    #[note(passes_unused_no_lints_note)]
     NoLints { name: Symbol },
-    #[note(passes::unused_default_method_body_const_note)]
+    #[note(passes_unused_default_method_body_const_note)]
     DefaultMethodBodyConst,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::unused)]
+#[diag(passes_unused)]
 pub struct Unused {
     #[suggestion(code = "", applicability = "machine-applicable")]
     pub attr_span: Span,
@@ -622,7 +626,7 @@ pub struct Unused {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::non_exported_macro_invalid_attrs, code = "E0518")]
+#[diag(passes_non_exported_macro_invalid_attrs, code = "E0518")]
 pub struct NonExportedMacroInvalidAttrs {
     #[primary_span]
     #[label]
@@ -630,7 +634,7 @@ pub struct NonExportedMacroInvalidAttrs {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::unused_duplicate)]
+#[diag(passes_unused_duplicate)]
 pub struct UnusedDuplicate {
     #[suggestion(code = "", applicability = "machine-applicable")]
     pub this: Span,
@@ -641,7 +645,7 @@ pub struct UnusedDuplicate {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unused_multiple)]
+#[diag(passes_unused_multiple)]
 pub struct UnusedMultiple {
     #[primary_span]
     #[suggestion(code = "", applicability = "machine-applicable")]
@@ -652,7 +656,7 @@ pub struct UnusedMultiple {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_lint_opt_ty)]
+#[diag(passes_rustc_lint_opt_ty)]
 pub struct RustcLintOptTy {
     #[primary_span]
     pub attr_span: Span,
@@ -661,7 +665,7 @@ pub struct RustcLintOptTy {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_lint_opt_deny_field_access)]
+#[diag(passes_rustc_lint_opt_deny_field_access)]
 pub struct RustcLintOptDenyFieldAccess {
     #[primary_span]
     pub attr_span: Span,
@@ -670,7 +674,7 @@ pub struct RustcLintOptDenyFieldAccess {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::collapse_debuginfo)]
+#[diag(passes_collapse_debuginfo)]
 pub struct CollapseDebuginfo {
     #[primary_span]
     pub attr_span: Span,
@@ -679,14 +683,14 @@ pub struct CollapseDebuginfo {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::deprecated_annotation_has_no_effect)]
+#[diag(passes_deprecated_annotation_has_no_effect)]
 pub struct DeprecatedAnnotationHasNoEffect {
     #[suggestion(applicability = "machine-applicable", code = "")]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unknown_external_lang_item, code = "E0264")]
+#[diag(passes_unknown_external_lang_item, code = "E0264")]
 pub struct UnknownExternLangItem {
     #[primary_span]
     pub span: Span,
@@ -694,19 +698,11 @@ pub struct UnknownExternLangItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::missing_panic_handler)]
+#[diag(passes_missing_panic_handler)]
 pub struct MissingPanicHandler;
 
 #[derive(Diagnostic)]
-#[diag(passes::alloc_func_required)]
-pub struct AllocFuncRequired;
-
-#[derive(Diagnostic)]
-#[diag(passes::missing_alloc_error_handler)]
-pub struct MissingAllocErrorHandler;
-
-#[derive(Diagnostic)]
-#[diag(passes::missing_lang_item)]
+#[diag(passes_missing_lang_item)]
 #[note]
 #[help]
 pub struct MissingLangItem {
@@ -714,7 +710,7 @@ pub struct MissingLangItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::lang_item_on_incorrect_target, code = "E0718")]
+#[diag(passes_lang_item_on_incorrect_target, code = "E0718")]
 pub struct LangItemOnIncorrectTarget {
     #[primary_span]
     #[label]
@@ -725,7 +721,7 @@ pub struct LangItemOnIncorrectTarget {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unknown_lang_item, code = "E0522")]
+#[diag(passes_unknown_lang_item, code = "E0522")]
 pub struct UnknownLangItem {
     #[primary_span]
     #[label]
@@ -740,12 +736,12 @@ pub struct InvalidAttrAtCrateLevel {
 }
 
 impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
+    #[track_caller]
     fn into_diagnostic(
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag =
-            handler.struct_err(rustc_errors::fluent::passes::invalid_attr_at_crate_level);
+        let mut diag = handler.struct_err(rustc_errors::fluent::passes_invalid_attr_at_crate_level);
         diag.set_span(self.span);
         diag.set_arg("name", self.name);
         // Only emit an error with a suggestion if we can create a string out
@@ -754,7 +750,7 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
             let replacement = src.replace("#!", "#");
             diag.span_suggestion_verbose(
                 self.span,
-                rustc_errors::fluent::passes::suggestion,
+                rustc_errors::fluent::suggestion,
                 replacement,
                 rustc_errors::Applicability::MachineApplicable,
             );
@@ -764,7 +760,7 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::duplicate_diagnostic_item)]
+#[diag(passes_duplicate_diagnostic_item)]
 pub struct DuplicateDiagnosticItem {
     #[primary_span]
     pub span: Span,
@@ -772,9 +768,9 @@ pub struct DuplicateDiagnosticItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::duplicate_diagnostic_item_in_crate)]
+#[diag(passes_duplicate_diagnostic_item_in_crate)]
 pub struct DuplicateDiagnosticItemInCrate {
-    #[note(passes::diagnostic_item_first_defined)]
+    #[note(passes_diagnostic_item_first_defined)]
     pub span: Option<Span>,
     pub orig_crate_name: Symbol,
     #[note]
@@ -784,7 +780,7 @@ pub struct DuplicateDiagnosticItemInCrate {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::abi)]
+#[diag(passes_abi)]
 pub struct Abi {
     #[primary_span]
     pub span: Span,
@@ -792,7 +788,7 @@ pub struct Abi {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::align)]
+#[diag(passes_align)]
 pub struct Align {
     #[primary_span]
     pub span: Span,
@@ -800,7 +796,7 @@ pub struct Align {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::size)]
+#[diag(passes_size)]
 pub struct Size {
     #[primary_span]
     pub span: Span,
@@ -808,7 +804,7 @@ pub struct Size {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::homogeneous_aggregate)]
+#[diag(passes_homogeneous_aggregate)]
 pub struct HomogeneousAggregate {
     #[primary_span]
     pub span: Span,
@@ -816,7 +812,7 @@ pub struct HomogeneousAggregate {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::layout_of)]
+#[diag(passes_layout_of)]
 pub struct LayoutOf {
     #[primary_span]
     pub span: Span,
@@ -825,7 +821,7 @@ pub struct LayoutOf {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unrecognized_field)]
+#[diag(passes_unrecognized_field)]
 pub struct UnrecognizedField {
     #[primary_span]
     pub span: Span,
@@ -833,7 +829,7 @@ pub struct UnrecognizedField {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::feature_stable_twice, code = "E0711")]
+#[diag(passes_feature_stable_twice, code = "E0711")]
 pub struct FeatureStableTwice {
     #[primary_span]
     pub span: Span,
@@ -843,7 +839,7 @@ pub struct FeatureStableTwice {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::feature_previously_declared, code = "E0711")]
+#[diag(passes_feature_previously_declared, code = "E0711")]
 pub struct FeaturePreviouslyDeclared<'a, 'b> {
     #[primary_span]
     pub span: Span,
@@ -853,7 +849,7 @@ pub struct FeaturePreviouslyDeclared<'a, 'b> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::expr_not_allowed_in_context, code = "E0744")]
+#[diag(passes_expr_not_allowed_in_context, code = "E0744")]
 pub struct ExprNotAllowedInContext<'a> {
     #[primary_span]
     pub span: Span,
@@ -873,23 +869,24 @@ pub struct BreakNonLoop<'a> {
 }
 
 impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
+    #[track_caller]
     fn into_diagnostic(
         self,
         handler: &rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
         let mut diag = handler.struct_span_err_with_code(
             self.span,
-            rustc_errors::fluent::passes::break_non_loop,
+            rustc_errors::fluent::passes_break_non_loop,
             error_code!(E0571),
         );
         diag.set_arg("kind", self.kind);
-        diag.span_label(self.span, rustc_errors::fluent::passes::label);
+        diag.span_label(self.span, rustc_errors::fluent::label);
         if let Some(head) = self.head {
-            diag.span_label(head, rustc_errors::fluent::passes::label2);
+            diag.span_label(head, rustc_errors::fluent::label2);
         }
         diag.span_suggestion(
             self.span,
-            rustc_errors::fluent::passes::suggestion,
+            rustc_errors::fluent::suggestion,
             self.suggestion,
             Applicability::MaybeIncorrect,
         );
@@ -907,7 +904,7 @@ impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
                 _ => {
                     diag.span_suggestion(
                         self.break_expr_span,
-                        rustc_errors::fluent::passes::break_expr_suggestion,
+                        rustc_errors::fluent::break_expr_suggestion,
                         label.ident,
                         Applicability::MaybeIncorrect,
                     );
@@ -919,39 +916,39 @@ impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::continue_labeled_block, code = "E0696")]
+#[diag(passes_continue_labeled_block, code = "E0696")]
 pub struct ContinueLabeledBlock {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::block_label)]
+    #[label(block_label)]
     pub block_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::break_inside_closure, code = "E0267")]
+#[diag(passes_break_inside_closure, code = "E0267")]
 pub struct BreakInsideClosure<'a> {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::closure_label)]
+    #[label(closure_label)]
     pub closure_span: Span,
     pub name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::break_inside_async_block, code = "E0267")]
+#[diag(passes_break_inside_async_block, code = "E0267")]
 pub struct BreakInsideAsyncBlock<'a> {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::async_block_label)]
+    #[label(async_block_label)]
     pub closure_span: Span,
     pub name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::outside_loop, code = "E0268")]
+#[diag(passes_outside_loop, code = "E0268")]
 pub struct OutsideLoop<'a> {
     #[primary_span]
     #[label]
@@ -960,7 +957,7 @@ pub struct OutsideLoop<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unlabeled_in_labeled_block, code = "E0695")]
+#[diag(passes_unlabeled_in_labeled_block, code = "E0695")]
 pub struct UnlabeledInLabeledBlock<'a> {
     #[primary_span]
     #[label]
@@ -969,7 +966,7 @@ pub struct UnlabeledInLabeledBlock<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unlabeled_cf_in_while_condition, code = "E0590")]
+#[diag(passes_unlabeled_cf_in_while_condition, code = "E0590")]
 pub struct UnlabeledCfInWhileCondition<'a> {
     #[primary_span]
     #[label]
@@ -978,25 +975,25 @@ pub struct UnlabeledCfInWhileCondition<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::cannot_inline_naked_function)]
+#[diag(passes_cannot_inline_naked_function)]
 pub struct CannotInlineNakedFunction {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::undefined_naked_function_abi)]
+#[diag(passes_undefined_naked_function_abi)]
 pub struct UndefinedNakedFunctionAbi;
 
 #[derive(Diagnostic)]
-#[diag(passes::no_patterns)]
+#[diag(passes_no_patterns)]
 pub struct NoPatterns {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::params_not_allowed)]
+#[diag(passes_params_not_allowed)]
 #[help]
 pub struct ParamsNotAllowed {
     #[primary_span]
@@ -1010,34 +1007,35 @@ pub struct NakedFunctionsAsmBlock {
 }
 
 impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock {
+    #[track_caller]
     fn into_diagnostic(
         self,
         handler: &rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
         let mut diag = handler.struct_span_err_with_code(
             self.span,
-            rustc_errors::fluent::passes::naked_functions_asm_block,
+            rustc_errors::fluent::passes_naked_functions_asm_block,
             error_code!(E0787),
         );
         for span in self.multiple_asms.iter() {
-            diag.span_label(*span, rustc_errors::fluent::passes::label_multiple_asm);
+            diag.span_label(*span, rustc_errors::fluent::label_multiple_asm);
         }
         for span in self.non_asms.iter() {
-            diag.span_label(*span, rustc_errors::fluent::passes::label_non_asm);
+            diag.span_label(*span, rustc_errors::fluent::label_non_asm);
         }
         diag
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::naked_functions_operands, code = "E0787")]
+#[diag(passes_naked_functions_operands, code = "E0787")]
 pub struct NakedFunctionsOperands {
     #[primary_span]
     pub unsupported_operands: Vec<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::naked_functions_asm_options, code = "E0787")]
+#[diag(passes_naked_functions_asm_options, code = "E0787")]
 pub struct NakedFunctionsAsmOptions {
     #[primary_span]
     pub span: Span,
@@ -1045,7 +1043,7 @@ pub struct NakedFunctionsAsmOptions {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::naked_functions_must_use_noreturn, code = "E0787")]
+#[diag(passes_naked_functions_must_use_noreturn, code = "E0787")]
 pub struct NakedFunctionsMustUseNoreturn {
     #[primary_span]
     pub span: Span,
@@ -1054,7 +1052,7 @@ pub struct NakedFunctionsMustUseNoreturn {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::attr_only_on_main)]
+#[diag(passes_attr_only_on_main)]
 pub struct AttrOnlyOnMain {
     #[primary_span]
     pub span: Span,
@@ -1062,7 +1060,7 @@ pub struct AttrOnlyOnMain {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::attr_only_on_root_main)]
+#[diag(passes_attr_only_on_root_main)]
 pub struct AttrOnlyOnRootMain {
     #[primary_span]
     pub span: Span,
@@ -1070,7 +1068,7 @@ pub struct AttrOnlyOnRootMain {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::attr_only_in_functions)]
+#[diag(passes_attr_only_in_functions)]
 pub struct AttrOnlyInFunctions {
     #[primary_span]
     pub span: Span,
@@ -1078,43 +1076,43 @@ pub struct AttrOnlyInFunctions {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::multiple_rustc_main, code = "E0137")]
+#[diag(passes_multiple_rustc_main, code = "E0137")]
 pub struct MultipleRustcMain {
     #[primary_span]
     pub span: Span,
-    #[label(passes::first)]
+    #[label(first)]
     pub first: Span,
-    #[label(passes::additional)]
+    #[label(additional)]
     pub additional: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::multiple_start_functions, code = "E0138")]
+#[diag(passes_multiple_start_functions, code = "E0138")]
 pub struct MultipleStartFunctions {
     #[primary_span]
     pub span: Span,
     #[label]
     pub labeled: Span,
-    #[label(passes::previous)]
+    #[label(previous)]
     pub previous: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::extern_main)]
+#[diag(passes_extern_main)]
 pub struct ExternMain {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unix_sigpipe_values)]
+#[diag(passes_unix_sigpipe_values)]
 pub struct UnixSigpipeValues {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::no_main_function, code = "E0601")]
+#[diag(passes_no_main_function, code = "E0601")]
 pub struct NoMainFunction {
     #[primary_span]
     pub span: Span,
@@ -1133,13 +1131,14 @@ pub struct NoMainErr {
 }
 
 impl<'a> IntoDiagnostic<'a> for NoMainErr {
+    #[track_caller]
     fn into_diagnostic(
         self,
         handler: &'a rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
         let mut diag = handler.struct_span_err_with_code(
             DUMMY_SP,
-            rustc_errors::fluent::passes::no_main_function,
+            rustc_errors::fluent::passes_no_main_function,
             error_code!(E0601),
         );
         diag.set_arg("crate_name", self.crate_name);
@@ -1147,16 +1146,16 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr {
         diag.set_arg("has_filename", self.has_filename);
         let note = if !self.non_main_fns.is_empty() {
             for &span in &self.non_main_fns {
-                diag.span_note(span, rustc_errors::fluent::passes::here_is_main);
+                diag.span_note(span, rustc_errors::fluent::here_is_main);
             }
-            diag.note(rustc_errors::fluent::passes::one_or_more_possible_main);
-            diag.help(rustc_errors::fluent::passes::consider_moving_main);
+            diag.note(rustc_errors::fluent::one_or_more_possible_main);
+            diag.help(rustc_errors::fluent::consider_moving_main);
             // There were some functions named `main` though. Try to give the user a hint.
-            rustc_errors::fluent::passes::main_must_be_defined_at_crate
+            rustc_errors::fluent::main_must_be_defined_at_crate
         } else if self.has_filename {
-            rustc_errors::fluent::passes::consider_adding_main_to_file
+            rustc_errors::fluent::consider_adding_main_to_file
         } else {
-            rustc_errors::fluent::passes::consider_adding_main_at_crate
+            rustc_errors::fluent::consider_adding_main_at_crate
         };
         if self.file_empty {
             diag.note(note);
@@ -1167,11 +1166,11 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr {
 
         if let Some(main_def) = self.main_def_opt && main_def.opt_fn_def_id().is_none(){
             // There is something at `crate::main`, but it is not a function definition.
-            diag.span_label(main_def.span, rustc_errors::fluent::passes::non_function_main);
+            diag.span_label(main_def.span, rustc_errors::fluent::non_function_main);
         }
 
         if self.add_teach_note {
-            diag.note(rustc_errors::fluent::passes::teach_note);
+            diag.note(rustc_errors::fluent::teach_note);
         }
         diag
     }
@@ -1193,17 +1192,18 @@ pub struct DuplicateLangItem {
 }
 
 impl IntoDiagnostic<'_> for DuplicateLangItem {
+    #[track_caller]
     fn into_diagnostic(
         self,
         handler: &rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
         let mut diag = handler.struct_err_with_code(
             match self.duplicate {
-                Duplicate::Plain => rustc_errors::fluent::passes::duplicate_lang_item,
+                Duplicate::Plain => rustc_errors::fluent::passes_duplicate_lang_item,
 
-                Duplicate::Crate => rustc_errors::fluent::passes::duplicate_lang_item_crate,
+                Duplicate::Crate => rustc_errors::fluent::passes_duplicate_lang_item_crate,
                 Duplicate::CrateDepends => {
-                    rustc_errors::fluent::passes::duplicate_lang_item_crate_depends
+                    rustc_errors::fluent::passes_duplicate_lang_item_crate_depends
                 }
             },
             error_code!(E0152),
@@ -1219,24 +1219,24 @@ impl IntoDiagnostic<'_> for DuplicateLangItem {
             diag.set_span(span);
         }
         if let Some(span) = self.first_defined_span {
-            diag.span_note(span, rustc_errors::fluent::passes::first_defined_span);
+            diag.span_note(span, rustc_errors::fluent::first_defined_span);
         } else {
             if self.orig_dependency_of.is_empty() {
-                diag.note(rustc_errors::fluent::passes::first_defined_crate);
+                diag.note(rustc_errors::fluent::first_defined_crate);
             } else {
-                diag.note(rustc_errors::fluent::passes::first_defined_crate_depends);
+                diag.note(rustc_errors::fluent::first_defined_crate_depends);
             }
 
             if self.orig_is_local {
-                diag.note(rustc_errors::fluent::passes::first_definition_local);
+                diag.note(rustc_errors::fluent::first_definition_local);
             } else {
-                diag.note(rustc_errors::fluent::passes::first_definition_path);
+                diag.note(rustc_errors::fluent::first_definition_path);
             }
 
             if self.is_local {
-                diag.note(rustc_errors::fluent::passes::second_definition_local);
+                diag.note(rustc_errors::fluent::second_definition_local);
             } else {
-                diag.note(rustc_errors::fluent::passes::second_definition_path);
+                diag.note(rustc_errors::fluent::second_definition_path);
             }
         }
         diag
@@ -1244,7 +1244,7 @@ impl IntoDiagnostic<'_> for DuplicateLangItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::incorrect_target, code = "E0718")]
+#[diag(passes_incorrect_target, code = "E0718")]
 pub struct IncorrectTarget<'a> {
     #[primary_span]
     pub span: Span,
@@ -1258,21 +1258,21 @@ pub struct IncorrectTarget<'a> {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::useless_assignment)]
+#[diag(passes_useless_assignment)]
 pub struct UselessAssignment<'a> {
     pub is_field_assign: bool,
     pub ty: Ty<'a>,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::only_has_effect_on)]
+#[diag(passes_only_has_effect_on)]
 pub struct OnlyHasEffectOn {
     pub attr_name: Symbol,
     pub target_name: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::object_lifetime_err)]
+#[diag(passes_object_lifetime_err)]
 pub struct ObjectLifetimeErr {
     #[primary_span]
     pub span: Span,
@@ -1280,7 +1280,7 @@ pub struct ObjectLifetimeErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unrecognized_repr_hint, code = "E0552")]
+#[diag(passes_unrecognized_repr_hint, code = "E0552")]
 #[help]
 pub struct UnrecognizedReprHint {
     #[primary_span]
@@ -1289,35 +1289,35 @@ pub struct UnrecognizedReprHint {
 
 #[derive(Diagnostic)]
 pub enum AttrApplication {
-    #[diag(passes::attr_application_enum, code = "E0517")]
+    #[diag(passes_attr_application_enum, code = "E0517")]
     Enum {
         #[primary_span]
         hint_span: Span,
         #[label]
         span: Span,
     },
-    #[diag(passes::attr_application_struct, code = "E0517")]
+    #[diag(passes_attr_application_struct, code = "E0517")]
     Struct {
         #[primary_span]
         hint_span: Span,
         #[label]
         span: Span,
     },
-    #[diag(passes::attr_application_struct_union, code = "E0517")]
+    #[diag(passes_attr_application_struct_union, code = "E0517")]
     StructUnion {
         #[primary_span]
         hint_span: Span,
         #[label]
         span: Span,
     },
-    #[diag(passes::attr_application_struct_enum_union, code = "E0517")]
+    #[diag(passes_attr_application_struct_enum_union, code = "E0517")]
     StructEnumUnion {
         #[primary_span]
         hint_span: Span,
         #[label]
         span: Span,
     },
-    #[diag(passes::attr_application_struct_enum_function_union, code = "E0517")]
+    #[diag(passes_attr_application_struct_enum_function_union, code = "E0517")]
     StructEnumFunctionUnion {
         #[primary_span]
         hint_span: Span,
@@ -1327,7 +1327,7 @@ pub enum AttrApplication {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::transparent_incompatible, code = "E0692")]
+#[diag(passes_transparent_incompatible, code = "E0692")]
 pub struct TransparentIncompatible {
     #[primary_span]
     pub hint_spans: Vec<Span>,
@@ -1335,54 +1335,54 @@ pub struct TransparentIncompatible {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::deprecated_attribute, code = "E0549")]
+#[diag(passes_deprecated_attribute, code = "E0549")]
 pub struct DeprecatedAttribute {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::useless_stability)]
+#[diag(passes_useless_stability)]
 pub struct UselessStability {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::item)]
+    #[label(item)]
     pub item_sp: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::invalid_stability)]
+#[diag(passes_invalid_stability)]
 pub struct InvalidStability {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::item)]
+    #[label(item)]
     pub item_sp: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::cannot_stabilize_deprecated)]
+#[diag(passes_cannot_stabilize_deprecated)]
 pub struct CannotStabilizeDeprecated {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::item)]
+    #[label(item)]
     pub item_sp: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::invalid_deprecation_version)]
+#[diag(passes_invalid_deprecation_version)]
 pub struct InvalidDeprecationVersion {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::item)]
+    #[label(item)]
     pub item_sp: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::missing_stability_attr)]
+#[diag(passes_missing_stability_attr)]
 pub struct MissingStabilityAttr<'a> {
     #[primary_span]
     pub span: Span,
@@ -1390,7 +1390,7 @@ pub struct MissingStabilityAttr<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::missing_const_stab_attr)]
+#[diag(passes_missing_const_stab_attr)]
 pub struct MissingConstStabAttr<'a> {
     #[primary_span]
     pub span: Span,
@@ -1398,7 +1398,7 @@ pub struct MissingConstStabAttr<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::trait_impl_const_stable)]
+#[diag(passes_trait_impl_const_stable)]
 #[note]
 pub struct TraitImplConstStable {
     #[primary_span]
@@ -1406,7 +1406,7 @@ pub struct TraitImplConstStable {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::feature_only_on_nightly, code = "E0554")]
+#[diag(passes_feature_only_on_nightly, code = "E0554")]
 pub struct FeatureOnlyOnNightly {
     #[primary_span]
     pub span: Span,
@@ -1414,7 +1414,7 @@ pub struct FeatureOnlyOnNightly {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unknown_feature, code = "E0635")]
+#[diag(passes_unknown_feature, code = "E0635")]
 pub struct UnknownFeature {
     #[primary_span]
     pub span: Span,
@@ -1422,7 +1422,7 @@ pub struct UnknownFeature {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::implied_feature_not_exist)]
+#[diag(passes_implied_feature_not_exist)]
 pub struct ImpliedFeatureNotExist {
     #[primary_span]
     pub span: Span,
@@ -1431,14 +1431,14 @@ pub struct ImpliedFeatureNotExist {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::duplicate_feature_err, code = "E0636")]
+#[diag(passes_duplicate_feature_err, code = "E0636")]
 pub struct DuplicateFeatureErr {
     #[primary_span]
     pub span: Span,
     pub feature: Symbol,
 }
 #[derive(Diagnostic)]
-#[diag(passes::missing_const_err)]
+#[diag(passes_missing_const_err)]
 pub struct MissingConstErr {
     #[primary_span]
     #[help]
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 3ee8c8bcb1d..88bb39debb1 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -126,7 +126,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
 
     fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
         let mut inner_visitor = self.new_visitor(self.hir_map);
-        inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
+        inner_visitor.check(i.owner_id, |this| intravisit::walk_item(this, i));
     }
 
     fn visit_id(&mut self, hir_id: HirId) {
@@ -148,16 +148,16 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
 
     fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
         let mut inner_visitor = self.new_visitor(self.hir_map);
-        inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
+        inner_visitor.check(i.owner_id, |this| intravisit::walk_foreign_item(this, i));
     }
 
     fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
         let mut inner_visitor = self.new_visitor(self.hir_map);
-        inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
+        inner_visitor.check(i.owner_id, |this| intravisit::walk_trait_item(this, i));
     }
 
     fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
         let mut inner_visitor = self.new_visitor(self.hir_map);
-        inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
+        inner_visitor.check(i.owner_id, |this| intravisit::walk_impl_item(this, i));
     }
 }
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 71b0735192a..188efc528ef 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -16,7 +16,7 @@ use crate::weak_lang_items;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS};
+use rustc_hir::lang_items::{extract, GenericRequirement};
 use rustc_hir::{HirId, LangItem, LanguageItems, Target};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::cstore::ExternCrate;
@@ -43,17 +43,17 @@ impl<'tcx> LanguageItemCollector<'tcx> {
     fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
         let attrs = self.tcx.hir().attrs(hir_id);
         if let Some((name, span)) = extract(&attrs) {
-            match ITEM_REFS.get(&name).cloned() {
+            match LangItem::from_name(name) {
                 // Known lang item with attribute on correct target.
-                Some((item_index, expected_target)) if actual_target == expected_target => {
-                    self.collect_item_extended(item_index, hir_id, span);
+                Some(lang_item) if actual_target == lang_item.target() => {
+                    self.collect_item_extended(lang_item, hir_id, span);
                 }
                 // Known lang item with attribute on incorrect target.
-                Some((_, expected_target)) => {
+                Some(lang_item) => {
                     self.tcx.sess.emit_err(LangItemOnIncorrectTarget {
                         span,
                         name,
-                        expected_target,
+                        expected_target: lang_item.target(),
                         actual_target,
                     });
                 }
@@ -65,12 +65,12 @@ impl<'tcx> LanguageItemCollector<'tcx> {
         }
     }
 
-    fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
+    fn collect_item(&mut self, lang_item: LangItem, item_def_id: DefId) {
         // Check for duplicates.
-        if let Some(original_def_id) = self.items.items[item_index] {
+        if let Some(original_def_id) = self.items.get(lang_item) {
             if original_def_id != item_def_id {
                 let local_span = self.tcx.hir().span_if_local(item_def_id);
-                let lang_item_name = LangItem::from_u32(item_index as u32).unwrap().name();
+                let lang_item_name = lang_item.name();
                 let crate_name = self.tcx.crate_name(item_def_id.krate);
                 let mut dependency_of = Empty;
                 let is_local = item_def_id.is_local();
@@ -139,17 +139,13 @@ impl<'tcx> LanguageItemCollector<'tcx> {
         }
 
         // Matched.
-        self.items.items[item_index] = Some(item_def_id);
-        if let Some(group) = LangItem::from_u32(item_index as u32).unwrap().group() {
-            self.items.groups[group as usize].push(item_def_id);
-        }
+        self.items.set(lang_item, item_def_id);
     }
 
     // Like collect_item() above, but also checks whether the lang item is declared
     // with the right number of generic arguments.
-    fn collect_item_extended(&mut self, item_index: usize, hir_id: HirId, span: Span) {
+    fn collect_item_extended(&mut self, lang_item: LangItem, hir_id: HirId, span: Span) {
         let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
-        let lang_item = LangItem::from_u32(item_index as u32).unwrap();
         let name = lang_item.name();
 
         // Now check whether the lang_item has the expected number of generic
@@ -197,7 +193,7 @@ impl<'tcx> LanguageItemCollector<'tcx> {
             }
         }
 
-        self.collect_item(item_index, item_def_id);
+        self.collect_item(lang_item, item_def_id);
     }
 }
 
@@ -208,8 +204,8 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems {
 
     // Collect lang items in other crates.
     for &cnum in tcx.crates(()).iter() {
-        for &(def_id, item_index) in tcx.defined_lang_items(cnum).iter() {
-            collector.collect_item(item_index, def_id);
+        for &(def_id, lang_item) in tcx.defined_lang_items(cnum).iter() {
+            collector.collect_item(lang_item, def_id);
         }
     }
 
@@ -217,9 +213,9 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems {
     let crate_items = tcx.hir_crate_items(());
 
     for id in crate_items.items() {
-        collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.def_id)), id.hir_id());
+        collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.owner_id)), id.hir_id());
 
-        if matches!(tcx.def_kind(id.def_id), DefKind::Enum) {
+        if matches!(tcx.def_kind(id.owner_id), DefKind::Enum) {
             let item = tcx.hir().item(id);
             if let hir::ItemKind::Enum(def, ..) = &item.kind {
                 for variant in def.variants {
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index c1085094962..5322baee747 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -15,11 +15,11 @@ pub fn test_layout(tcx: TyCtxt<'_>) {
         // if the `rustc_attrs` feature is not enabled, don't bother testing layout
         for id in tcx.hir().items() {
             if matches!(
-                tcx.def_kind(id.def_id),
+                tcx.def_kind(id.owner_id),
                 DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
             ) {
-                for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) {
-                    dump_layout_of(tcx, id.def_id.def_id, attr);
+                for attr in tcx.get_attrs(id.owner_id.to_def_id(), sym::rustc_layout) {
+                    dump_layout_of(tcx, id.owner_id.def_id, attr);
                 }
             }
         }
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 0f2879c1eff..73ea06a6370 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -12,7 +12,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::Node;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
-use rustc_middle::middle::privacy::{self, AccessLevel};
+use rustc_middle::middle::privacy::{self, Level};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::config::CrateType;
@@ -29,7 +29,7 @@ fn item_might_be_inlined(tcx: TyCtxt<'_>, item: &hir::Item<'_>, attrs: &CodegenF
     match item.kind {
         hir::ItemKind::Fn(ref sig, ..) if sig.header.is_const() => true,
         hir::ItemKind::Impl { .. } | hir::ItemKind::Fn(..) => {
-            let generics = tcx.generics_of(item.def_id);
+            let generics = tcx.generics_of(item.owner_id);
             generics.requires_monomorphization(tcx)
         }
         _ => false,
@@ -42,7 +42,7 @@ fn method_might_be_inlined(
     impl_src: LocalDefId,
 ) -> bool {
     let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id().owner.to_def_id());
-    let generics = tcx.generics_of(impl_item.def_id);
+    let generics = tcx.generics_of(impl_item.owner_id);
     if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) {
         return true;
     }
@@ -216,7 +216,7 @@ impl<'tcx> ReachableContext<'tcx> {
                         if item_might_be_inlined(
                             self.tcx,
                             &item,
-                            self.tcx.codegen_fn_attrs(item.def_id),
+                            self.tcx.codegen_fn_attrs(item.owner_id),
                         ) {
                             self.visit_nested_body(body);
                         }
@@ -303,13 +303,13 @@ fn check_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     id: hir::ItemId,
     worklist: &mut Vec<LocalDefId>,
-    access_levels: &privacy::AccessLevels,
+    effective_visibilities: &privacy::EffectiveVisibilities,
 ) {
-    if has_custom_linkage(tcx, id.def_id.def_id) {
-        worklist.push(id.def_id.def_id);
+    if has_custom_linkage(tcx, id.owner_id.def_id) {
+        worklist.push(id.owner_id.def_id);
     }
 
-    if !matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
+    if !matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
         return;
     }
 
@@ -318,8 +318,8 @@ fn check_item<'tcx>(
     if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
         item.kind
     {
-        if !access_levels.is_reachable(item.def_id.def_id) {
-            worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id.def_id));
+        if !effective_visibilities.is_reachable(item.owner_id.def_id) {
+            worklist.extend(items.iter().map(|ii_ref| ii_ref.id.owner_id.def_id));
 
             let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
                 unreachable!();
@@ -354,7 +354,7 @@ fn has_custom_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
 }
 
 fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
-    let access_levels = &tcx.privacy_access_levels(());
+    let effective_visibilities = &tcx.effective_visibilities(());
 
     let any_library =
         tcx.sess.crate_types().iter().any(|ty| {
@@ -373,18 +373,16 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
     //         If other crates link to us, they're going to expect to be able to
     //         use the lang items, so we need to be sure to mark them as
     //         exported.
-    reachable_context.worklist = access_levels
+    reachable_context.worklist = effective_visibilities
         .iter()
         .filter_map(|(&id, effective_vis)| {
-            effective_vis.is_public_at_level(AccessLevel::ReachableFromImplTrait).then_some(id)
+            effective_vis.is_public_at_level(Level::ReachableThroughImplTrait).then_some(id)
         })
         .collect::<Vec<_>>();
 
-    for item in tcx.lang_items().items().iter() {
-        if let Some(def_id) = *item {
-            if let Some(def_id) = def_id.as_local() {
-                reachable_context.worklist.push(def_id);
-            }
+    for (_, def_id) in tcx.lang_items().iter() {
+        if let Some(def_id) = def_id.as_local() {
+            reachable_context.worklist.push(def_id);
         }
     }
     {
@@ -399,12 +397,12 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
         let crate_items = tcx.hir_crate_items(());
 
         for id in crate_items.items() {
-            check_item(tcx, id, &mut reachable_context.worklist, access_levels);
+            check_item(tcx, id, &mut reachable_context.worklist, effective_visibilities);
         }
 
         for id in crate_items.impl_items() {
-            if has_custom_linkage(tcx, id.def_id.def_id) {
-                reachable_context.worklist.push(id.def_id.def_id);
+            if has_custom_linkage(tcx, id.owner_id.def_id) {
+                reachable_context.worklist.push(id.owner_id.def_id);
             }
         }
     }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index cfd6acd8d7c..78afa2f25f8 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -20,7 +20,7 @@ use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
 use rustc_middle::ty::{query::Providers, TyCtxt};
 use rustc_session::lint;
@@ -378,7 +378,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         }
 
         self.annotate(
-            i.def_id.def_id,
+            i.owner_id.def_id,
             i.span,
             fn_sig,
             kind,
@@ -397,7 +397,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         };
 
         self.annotate(
-            ti.def_id.def_id,
+            ti.owner_id.def_id,
             ti.span,
             fn_sig,
             AnnotationKind::Required,
@@ -420,7 +420,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         };
 
         self.annotate(
-            ii.def_id.def_id,
+            ii.owner_id.def_id,
             ii.span,
             fn_sig,
             kind,
@@ -478,7 +478,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
 
     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
         self.annotate(
-            i.def_id.def_id,
+            i.owner_id.def_id,
             i.span,
             None,
             AnnotationKind::Required,
@@ -516,13 +516,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
 
 struct MissingStabilityAnnotations<'tcx> {
     tcx: TyCtxt<'tcx>,
-    access_levels: &'tcx AccessLevels,
+    effective_visibilities: &'tcx EffectiveVisibilities,
 }
 
 impl<'tcx> MissingStabilityAnnotations<'tcx> {
     fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
         let stab = self.tcx.stability().local_stability(def_id);
-        if !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(def_id) {
+        if !self.tcx.sess.opts.test
+            && stab.is_none()
+            && self.effective_visibilities.is_reachable(def_id)
+        {
             let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
             self.tcx.sess.emit_err(MissingStabilityAttr { span, descr });
         }
@@ -540,7 +543,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
             .lookup_stability(def_id)
             .map_or(false, |stability| stability.level.is_stable());
         let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none();
-        let is_reachable = self.access_levels.is_reachable(def_id);
+        let is_reachable = self.effective_visibilities.is_reachable(def_id);
 
         if is_const && is_stable && missing_const_stability_attribute && is_reachable {
             let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
@@ -566,25 +569,25 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
             hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
                 | hir::ItemKind::ForeignMod { .. }
         ) {
-            self.check_missing_stability(i.def_id.def_id, i.span);
+            self.check_missing_stability(i.owner_id.def_id, i.span);
         }
 
         // Ensure stable `const fn` have a const stability attribute.
-        self.check_missing_const_stability(i.def_id.def_id, i.span);
+        self.check_missing_const_stability(i.owner_id.def_id, i.span);
 
         intravisit::walk_item(self, i)
     }
 
     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
-        self.check_missing_stability(ti.def_id.def_id, ti.span);
+        self.check_missing_stability(ti.owner_id.def_id, ti.span);
         intravisit::walk_trait_item(self, ti);
     }
 
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
         let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id());
         if self.tcx.impl_trait_ref(impl_def_id).is_none() {
-            self.check_missing_stability(ii.def_id.def_id, ii.span);
-            self.check_missing_const_stability(ii.def_id.def_id, ii.span);
+            self.check_missing_stability(ii.owner_id.def_id, ii.span);
+            self.check_missing_const_stability(ii.owner_id.def_id, ii.span);
         }
         intravisit::walk_impl_item(self, ii);
     }
@@ -603,7 +606,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
     }
 
     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
-        self.check_missing_stability(i.def_id.def_id, i.span);
+        self.check_missing_stability(i.owner_id.def_id, i.span);
         intravisit::walk_foreign_item(self, i);
     }
     // Note that we don't need to `check_missing_stability` for default generic parameters,
@@ -709,7 +712,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                     return;
                 }
 
-                let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.def_id.def_id) else {
+                let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.owner_id.def_id) else {
                     return;
                 };
                 let def_id = cnum.as_def_id();
@@ -762,7 +765,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                 }
 
                 for impl_item_ref in *items {
-                    let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
+                    let impl_item = self.tcx.associated_item(impl_item_ref.id.owner_id);
 
                     if let Some(def_id) = impl_item.trait_item_def_id {
                         // Pass `None` to skip deprecation warnings.
@@ -891,8 +894,25 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
         if let TyKind::Never = t.kind {
             self.fully_stable = false;
         }
+        if let TyKind::BareFn(f) = t.kind {
+            if rustc_target::spec::abi::is_stable(f.abi.name()).is_err() {
+                self.fully_stable = false;
+            }
+        }
         intravisit::walk_ty(self, t)
     }
+
+    fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
+        for ty in fd.inputs {
+            self.visit_ty(ty)
+        }
+        if let hir::FnRetTy::Return(output_ty) = fd.output {
+            match output_ty.kind {
+                TyKind::Never => {} // `-> !` is stable
+                _ => self.visit_ty(output_ty),
+            }
+        }
+    }
 }
 
 /// Given the list of enabled features that were not language features (i.e., that
@@ -902,8 +922,8 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     let is_staged_api =
         tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api;
     if is_staged_api {
-        let access_levels = &tcx.privacy_access_levels(());
-        let mut missing = MissingStabilityAnnotations { tcx, access_levels };
+        let effective_visibilities = &tcx.effective_visibilities(());
+        let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
         missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
         tcx.hir().walk_toplevel_module(&mut missing);
         tcx.hir().visit_all_item_likes_in_crate(&mut missing);
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 92024989a75..f0815fcd8db 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -2,15 +2,12 @@
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::lang_items::{self, LangItem};
-use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
+use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
 use rustc_middle::middle::lang_items::required;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
 
-use crate::errors::{
-    AllocFuncRequired, MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler,
-    UnknownExternLangItem,
-};
+use crate::errors::{MissingLangItem, MissingPanicHandler, UnknownExternLangItem};
 
 /// Checks the crate for usage of weak lang items, returning a vector of all the
 /// language items required by this crate, but not defined yet.
@@ -29,12 +26,12 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem
     for id in crate_items.foreign_items() {
         let attrs = tcx.hir().attrs(id.hir_id());
         if let Some((lang_item, _)) = lang_items::extract(attrs) {
-            if let Some(&item) = WEAK_ITEMS_REFS.get(&lang_item) {
-                if items.require(item).is_err() {
+            if let Some(item) = LangItem::from_name(lang_item) && item.is_weak() {
+                if items.get(item).is_none() {
                     items.missing.push(item);
                 }
             } else {
-                let span = tcx.def_span(id.def_id);
+                let span = tcx.def_span(id.owner_id);
                 tcx.sess.emit_err(UnknownExternLangItem { span, lang_item });
             }
         }
@@ -65,17 +62,12 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
         }
     }
 
-    for (name, &item) in WEAK_ITEMS_REFS.iter() {
-        if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() {
+    for &item in WEAK_LANG_ITEMS.iter() {
+        if missing.contains(&item) && required(tcx, item) && items.get(item).is_none() {
             if item == LangItem::PanicImpl {
                 tcx.sess.emit_err(MissingPanicHandler);
-            } else if item == LangItem::Oom {
-                if !tcx.features().default_alloc_error_handler {
-                    tcx.sess.emit_err(AllocFuncRequired);
-                    tcx.sess.emit_note(MissingAllocErrorHandler);
-                }
             } else {
-                tcx.sess.emit_err(MissingLangItem { name: *name });
+                tcx.sess.emit_err(MissingLangItem { name: item.name() });
             }
         }
     }
diff --git a/compiler/rustc_plugin_impl/src/errors.rs b/compiler/rustc_plugin_impl/src/errors.rs
index 07ce92a9b26..e6a7fc86bee 100644
--- a/compiler/rustc_plugin_impl/src/errors.rs
+++ b/compiler/rustc_plugin_impl/src/errors.rs
@@ -4,7 +4,7 @@ use rustc_macros::Diagnostic;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(plugin_impl::load_plugin_error)]
+#[diag(plugin_impl_load_plugin_error)]
 pub struct LoadPluginError {
     #[primary_span]
     pub span: Span,
@@ -12,7 +12,7 @@ pub struct LoadPluginError {
 }
 
 #[derive(Diagnostic)]
-#[diag(plugin_impl::malformed_plugin_attribute, code = "E0498")]
+#[diag(plugin_impl_malformed_plugin_attribute, code = "E0498")]
 pub struct MalformedPluginAttribute {
     #[primary_span]
     #[label]
diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs
index f3a617c2f0f..a6c95f1a815 100644
--- a/compiler/rustc_privacy/src/errors.rs
+++ b/compiler/rustc_privacy/src/errors.rs
@@ -3,7 +3,7 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
-#[diag(privacy::field_is_private, code = "E0451")]
+#[diag(privacy_field_is_private, code = "E0451")]
 pub struct FieldIsPrivate {
     #[primary_span]
     pub span: Span,
@@ -16,13 +16,13 @@ pub struct FieldIsPrivate {
 
 #[derive(Subdiagnostic)]
 pub enum FieldIsPrivateLabel {
-    #[label(privacy::field_is_private_is_update_syntax_label)]
+    #[label(privacy_field_is_private_is_update_syntax_label)]
     IsUpdateSyntax {
         #[primary_span]
         span: Span,
         field_name: Symbol,
     },
-    #[label(privacy::field_is_private_label)]
+    #[label(privacy_field_is_private_label)]
     Other {
         #[primary_span]
         span: Span,
@@ -30,7 +30,7 @@ pub enum FieldIsPrivateLabel {
 }
 
 #[derive(Diagnostic)]
-#[diag(privacy::item_is_private)]
+#[diag(privacy_item_is_private)]
 pub struct ItemIsPrivate<'a> {
     #[primary_span]
     #[label]
@@ -40,7 +40,7 @@ pub struct ItemIsPrivate<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(privacy::unnamed_item_is_private)]
+#[diag(privacy_unnamed_item_is_private)]
 pub struct UnnamedItemIsPrivate {
     #[primary_span]
     pub span: Span,
@@ -49,7 +49,7 @@ pub struct UnnamedItemIsPrivate {
 
 // Duplicate of `InPublicInterface` but with a different error code, shares the same slug.
 #[derive(Diagnostic)]
-#[diag(privacy::in_public_interface, code = "E0445")]
+#[diag(privacy_in_public_interface, code = "E0445")]
 pub struct InPublicInterfaceTraits<'a> {
     #[primary_span]
     #[label]
@@ -57,13 +57,13 @@ pub struct InPublicInterfaceTraits<'a> {
     pub vis_descr: &'static str,
     pub kind: &'a str,
     pub descr: DiagnosticArgFromDisplay<'a>,
-    #[label(privacy::visibility_label)]
+    #[label(visibility_label)]
     pub vis_span: Span,
 }
 
 // Duplicate of `InPublicInterfaceTraits` but with a different error code, shares the same slug.
 #[derive(Diagnostic)]
-#[diag(privacy::in_public_interface, code = "E0446")]
+#[diag(privacy_in_public_interface, code = "E0446")]
 pub struct InPublicInterface<'a> {
     #[primary_span]
     #[label]
@@ -71,12 +71,12 @@ pub struct InPublicInterface<'a> {
     pub vis_descr: &'static str,
     pub kind: &'a str,
     pub descr: DiagnosticArgFromDisplay<'a>,
-    #[label(privacy::visibility_label)]
+    #[label(visibility_label)]
     pub vis_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(privacy::report_effective_visibility)]
+#[diag(privacy_report_effective_visibility)]
 pub struct ReportEffectiveVisibility {
     #[primary_span]
     pub span: Span,
@@ -84,7 +84,7 @@ pub struct ReportEffectiveVisibility {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(privacy::from_private_dep_in_public_interface)]
+#[diag(privacy_from_private_dep_in_public_interface)]
 pub struct FromPrivateDependencyInPublicInterface<'a> {
     pub kind: &'a str,
     pub descr: DiagnosticArgFromDisplay<'a>,
@@ -92,7 +92,7 @@ pub struct FromPrivateDependencyInPublicInterface<'a> {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(privacy::private_in_public_lint)]
+#[diag(privacy_private_in_public_lint)]
 pub struct PrivateInPublicLint<'a> {
     pub vis_descr: &'static str,
     pub kind: &'a str,
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index e904fab4d76..865d6306bd3 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -23,7 +23,7 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
+use rustc_middle::middle::privacy::{EffectiveVisibilities, Level};
 use rustc_middle::span_bug;
 use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst, Node as ACNode};
 use rustc_middle::ty::query::Providers;
@@ -159,34 +159,12 @@ where
                 ty.visit_with(self)
             }
             ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE,
-            ty::PredicateKind::ConstEvaluatable(uv)
-                if self.def_id_visitor.tcx().features().generic_const_exprs =>
-            {
-                let tcx = self.def_id_visitor.tcx();
-                if let Ok(Some(ct)) = AbstractConst::new(tcx, uv) {
-                    self.visit_abstract_const_expr(tcx, ct)?;
-                }
-                ControlFlow::CONTINUE
-            }
+            ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self),
             ty::PredicateKind::WellFormed(arg) => arg.visit_with(self),
             _ => bug!("unexpected predicate: {:?}", predicate),
         }
     }
 
-    fn visit_abstract_const_expr(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        ct: AbstractConst<'tcx>,
-    ) -> ControlFlow<V::BreakTy> {
-        walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
-            ACNode::Leaf(leaf) => self.visit_const(leaf),
-            ACNode::Cast(_, _, ty) => self.visit_ty(ty),
-            ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
-                ControlFlow::CONTINUE
-            }
-        })
-    }
-
     fn visit_predicates(
         &mut self,
         predicates: ty::GenericPredicates<'tcx>,
@@ -309,9 +287,16 @@ where
         self.visit_ty(c.ty())?;
         let tcx = self.def_id_visitor.tcx();
         if let Ok(Some(ct)) = AbstractConst::from_const(tcx, c) {
-            self.visit_abstract_const_expr(tcx, ct)?;
+            walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
+                ACNode::Leaf(leaf) => self.visit_const(leaf),
+                ACNode::Cast(_, _, ty) => self.visit_ty(ty),
+                ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
+                    ControlFlow::CONTINUE
+                }
+            })
+        } else {
+            ControlFlow::CONTINUE
         }
-        ControlFlow::CONTINUE
     }
 }
 
@@ -325,7 +310,7 @@ fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visib
 
 struct FindMin<'a, 'tcx, VL: VisibilityLike> {
     tcx: TyCtxt<'tcx>,
-    access_levels: &'a AccessLevels,
+    effective_visibilities: &'a EffectiveVisibilities,
     min: VL,
 }
 
@@ -359,8 +344,12 @@ trait VisibilityLike: Sized {
 
     // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
     // associated types for which we can't determine visibility precisely.
-    fn of_impl(def_id: LocalDefId, tcx: TyCtxt<'_>, access_levels: &AccessLevels) -> Self {
-        let mut find = FindMin { tcx, access_levels, min: Self::MAX };
+    fn of_impl(
+        def_id: LocalDefId,
+        tcx: TyCtxt<'_>,
+        effective_visibilities: &EffectiveVisibilities,
+    ) -> Self {
+        let mut find = FindMin { tcx, effective_visibilities, min: Self::MAX };
         find.visit(tcx.type_of(def_id));
         if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
             find.visit_trait(trait_ref);
@@ -374,8 +363,8 @@ impl VisibilityLike for ty::Visibility {
         min(find.tcx.local_visibility(def_id), find.min, find.tcx)
     }
 }
-impl VisibilityLike for Option<AccessLevel> {
-    const MAX: Self = Some(AccessLevel::Public);
+impl VisibilityLike for Option<Level> {
+    const MAX: Self = Some(Level::Direct);
     // Type inference is very smart sometimes.
     // It can make an impl reachable even some components of its type or trait are unreachable.
     // E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }`
@@ -387,7 +376,7 @@ impl VisibilityLike for Option<AccessLevel> {
     // (which require reaching the `DefId`s in them).
     const SHALLOW: bool = true;
     fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
-        cmp::min(find.access_levels.get_access_level(def_id), find.min)
+        cmp::min(find.effective_visibilities.public_at_level(def_id), find.min)
     }
 }
 
@@ -398,8 +387,8 @@ impl VisibilityLike for Option<AccessLevel> {
 struct EmbargoVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
 
-    /// Accessibility levels for reachable nodes.
-    access_levels: AccessLevels,
+    /// Effective visibilities for reachable nodes.
+    effective_visibilities: EffectiveVisibilities,
     /// A set of pairs corresponding to modules, where the first module is
     /// reachable via a macro that's defined in the second module. This cannot
     /// be represented as reachable because it can't handle the following case:
@@ -413,38 +402,38 @@ struct EmbargoVisitor<'tcx> {
     ///     n::p::f()
     /// }
     macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>,
-    /// Previous accessibility level; `None` means unreachable.
-    prev_level: Option<AccessLevel>,
+    /// Previous visibility level; `None` means unreachable.
+    prev_level: Option<Level>,
     /// Has something changed in the level map?
     changed: bool,
 }
 
 struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
-    access_level: Option<AccessLevel>,
+    level: Option<Level>,
     item_def_id: LocalDefId,
     ev: &'a mut EmbargoVisitor<'tcx>,
 }
 
 impl<'tcx> EmbargoVisitor<'tcx> {
-    fn get(&self, def_id: LocalDefId) -> Option<AccessLevel> {
-        self.access_levels.get_access_level(def_id)
+    fn get(&self, def_id: LocalDefId) -> Option<Level> {
+        self.effective_visibilities.public_at_level(def_id)
     }
 
-    fn update_with_hir_id(
-        &mut self,
-        hir_id: hir::HirId,
-        level: Option<AccessLevel>,
-    ) -> Option<AccessLevel> {
+    fn update_with_hir_id(&mut self, hir_id: hir::HirId, level: Option<Level>) -> Option<Level> {
         let def_id = self.tcx.hir().local_def_id(hir_id);
         self.update(def_id, level)
     }
 
     /// Updates node level and returns the updated level.
-    fn update(&mut self, def_id: LocalDefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
+    fn update(&mut self, def_id: LocalDefId, level: Option<Level>) -> Option<Level> {
         let old_level = self.get(def_id);
-        // Accessibility levels can only grow.
+        // Visibility levels can only grow.
         if level > old_level {
-            self.access_levels.set_access_level(def_id, level.unwrap());
+            self.effective_visibilities.set_public_at_level(
+                def_id,
+                || ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)),
+                level.unwrap(),
+            );
             self.changed = true;
             level
         } else {
@@ -455,10 +444,10 @@ impl<'tcx> EmbargoVisitor<'tcx> {
     fn reach(
         &mut self,
         def_id: LocalDefId,
-        access_level: Option<AccessLevel>,
+        level: Option<Level>,
     ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
         ReachEverythingInTheInterfaceVisitor {
-            access_level: cmp::min(access_level, Some(AccessLevel::Reachable)),
+            level: cmp::min(level, Some(Level::Reachable)),
             item_def_id: def_id,
             ev: self,
         }
@@ -516,9 +505,9 @@ impl<'tcx> EmbargoVisitor<'tcx> {
     fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod: LocalDefId) {
         let module = self.tcx.hir().get_module(module_def_id).0;
         for item_id in module.item_ids {
-            let def_kind = self.tcx.def_kind(item_id.def_id);
-            let vis = self.tcx.local_visibility(item_id.def_id.def_id);
-            self.update_macro_reachable_def(item_id.def_id.def_id, def_kind, vis, defining_mod);
+            let def_kind = self.tcx.def_kind(item_id.owner_id);
+            let vis = self.tcx.local_visibility(item_id.owner_id.def_id);
+            self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod);
         }
         if let Some(exports) = self.tcx.module_reexports(module_def_id) {
             for export in exports {
@@ -541,7 +530,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         vis: ty::Visibility,
         module: LocalDefId,
     ) {
-        let level = Some(AccessLevel::Reachable);
+        let level = Some(Level::Reachable);
         if vis.is_public() {
             self.update(def_id, level);
         }
@@ -638,14 +627,14 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         let item_level = match item.kind {
             hir::ItemKind::Impl { .. } => {
-                let impl_level = Option::<AccessLevel>::of_impl(
-                    item.def_id.def_id,
+                let impl_level = Option::<Level>::of_impl(
+                    item.owner_id.def_id,
                     self.tcx,
-                    &self.access_levels,
+                    &self.effective_visibilities,
                 );
-                self.update(item.def_id.def_id, impl_level)
+                self.update(item.owner_id.def_id, impl_level)
             }
-            _ => self.get(item.def_id.def_id),
+            _ => self.get(item.owner_id.def_id),
         };
 
         // Update levels of nested things.
@@ -664,15 +653,15 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             hir::ItemKind::Impl(ref impl_) => {
                 for impl_item_ref in impl_.items {
                     if impl_.of_trait.is_some()
-                        || self.tcx.visibility(impl_item_ref.id.def_id).is_public()
+                        || self.tcx.visibility(impl_item_ref.id.owner_id).is_public()
                     {
-                        self.update(impl_item_ref.id.def_id.def_id, item_level);
+                        self.update(impl_item_ref.id.owner_id.def_id, item_level);
                     }
                 }
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
                 for trait_item_ref in trait_item_refs {
-                    self.update(trait_item_ref.id.def_id.def_id, item_level);
+                    self.update(trait_item_ref.id.owner_id.def_id, item_level);
                 }
             }
             hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
@@ -688,12 +677,12 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                 }
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
-                self.update_reachability_from_macro(item.def_id.def_id, macro_def);
+                self.update_reachability_from_macro(item.owner_id.def_id, macro_def);
             }
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    if self.tcx.visibility(foreign_item.id.def_id).is_public() {
-                        self.update(foreign_item.id.def_id.def_id, item_level);
+                    if self.tcx.visibility(foreign_item.id.owner_id).is_public() {
+                        self.update(foreign_item.id.owner_id.def_id, item_level);
                     }
                 }
             }
@@ -716,7 +705,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {}
             // All nested items are checked by `visit_item`.
             hir::ItemKind::Mod(..) => {}
-            // Handled in the access level of in rustc_resolve
+            // Handled in `rustc_resolve`.
             hir::ItemKind::Use(..) => {}
             // The interface is empty.
             hir::ItemKind::GlobalAsm(..) => {}
@@ -729,9 +718,8 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     // FIXME: This is some serious pessimization intended to workaround deficiencies
                     // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
                     // reachable if they are returned via `impl Trait`, even from private functions.
-                    let exist_level =
-                        cmp::max(item_level, Some(AccessLevel::ReachableFromImplTrait));
-                    self.reach(item.def_id.def_id, exist_level).generics().predicates().ty();
+                    let exist_level = cmp::max(item_level, Some(Level::ReachableThroughImplTrait));
+                    self.reach(item.owner_id.def_id, exist_level).generics().predicates().ty();
                 }
             }
             // Visit everything.
@@ -740,20 +728,20 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             | hir::ItemKind::Fn(..)
             | hir::ItemKind::TyAlias(..) => {
                 if item_level.is_some() {
-                    self.reach(item.def_id.def_id, item_level).generics().predicates().ty();
+                    self.reach(item.owner_id.def_id, item_level).generics().predicates().ty();
                 }
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
                 if item_level.is_some() {
-                    self.reach(item.def_id.def_id, item_level).generics().predicates();
+                    self.reach(item.owner_id.def_id, item_level).generics().predicates();
 
                     for trait_item_ref in trait_item_refs {
                         let tcx = self.tcx;
-                        let mut reach = self.reach(trait_item_ref.id.def_id.def_id, item_level);
+                        let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_level);
                         reach.generics().predicates();
 
                         if trait_item_ref.kind == AssocItemKind::Type
-                            && !tcx.impl_defaultness(trait_item_ref.id.def_id).has_value()
+                            && !tcx.impl_defaultness(trait_item_ref.id.owner_id).has_value()
                         {
                             // No type to visit.
                         } else {
@@ -764,22 +752,22 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
             hir::ItemKind::TraitAlias(..) => {
                 if item_level.is_some() {
-                    self.reach(item.def_id.def_id, item_level).generics().predicates();
+                    self.reach(item.owner_id.def_id, item_level).generics().predicates();
                 }
             }
             // Visit everything except for private impl items.
             hir::ItemKind::Impl(ref impl_) => {
                 if item_level.is_some() {
-                    self.reach(item.def_id.def_id, item_level)
+                    self.reach(item.owner_id.def_id, item_level)
                         .generics()
                         .predicates()
                         .ty()
                         .trait_ref();
 
                     for impl_item_ref in impl_.items {
-                        let impl_item_level = self.get(impl_item_ref.id.def_id.def_id);
+                        let impl_item_level = self.get(impl_item_ref.id.owner_id.def_id);
                         if impl_item_level.is_some() {
-                            self.reach(impl_item_ref.id.def_id.def_id, impl_item_level)
+                            self.reach(impl_item_ref.id.owner_id.def_id, impl_item_level)
                                 .generics()
                                 .predicates()
                                 .ty();
@@ -791,7 +779,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             // Visit everything, but enum variants have their own levels.
             hir::ItemKind::Enum(ref def, _) => {
                 if item_level.is_some() {
-                    self.reach(item.def_id.def_id, item_level).generics().predicates();
+                    self.reach(item.owner_id.def_id, item_level).generics().predicates();
                 }
                 for variant in def.variants {
                     let variant_level = self.get(self.tcx.hir().local_def_id(variant.id));
@@ -802,13 +790,13 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                         }
                         // Corner case: if the variant is reachable, but its
                         // enum is not, make the enum reachable as well.
-                        self.reach(item.def_id.def_id, variant_level).ty();
+                        self.reach(item.owner_id.def_id, variant_level).ty();
                     }
                     if let Some(hir_id) = variant.data.ctor_hir_id() {
                         let ctor_def_id = self.tcx.hir().local_def_id(hir_id);
                         let ctor_level = self.get(ctor_def_id);
                         if ctor_level.is_some() {
-                            self.reach(item.def_id.def_id, ctor_level).ty();
+                            self.reach(item.owner_id.def_id, ctor_level).ty();
                         }
                     }
                 }
@@ -816,9 +804,9 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             // Visit everything, but foreign items have their own levels.
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    let foreign_item_level = self.get(foreign_item.id.def_id.def_id);
+                    let foreign_item_level = self.get(foreign_item.id.owner_id.def_id);
                     if foreign_item_level.is_some() {
-                        self.reach(foreign_item.id.def_id.def_id, foreign_item_level)
+                        self.reach(foreign_item.id.owner_id.def_id, foreign_item_level)
                             .generics()
                             .predicates()
                             .ty();
@@ -828,7 +816,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             // Visit everything except for private fields.
             hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
                 if item_level.is_some() {
-                    self.reach(item.def_id.def_id, item_level).generics().predicates();
+                    self.reach(item.owner_id.def_id, item_level).generics().predicates();
                     for field in struct_def.fields() {
                         let def_id = self.tcx.hir().local_def_id(field.hir_id);
                         let field_level = self.get(def_id);
@@ -841,7 +829,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     let ctor_def_id = self.tcx.hir().local_def_id(hir_id);
                     let ctor_level = self.get(ctor_def_id);
                     if ctor_level.is_some() {
-                        self.reach(item.def_id.def_id, ctor_level).ty();
+                        self.reach(item.owner_id.def_id, ctor_level).ty();
                     }
                 }
             }
@@ -912,10 +900,10 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx>
         _descr: &dyn fmt::Display,
     ) -> ControlFlow<Self::BreakTy> {
         if let Some(def_id) = def_id.as_local() {
-            if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) =
-                (self.tcx().visibility(def_id.to_def_id()), self.access_level)
+            if let (ty::Visibility::Public, _) | (_, Some(Level::ReachableThroughImplTrait)) =
+                (self.tcx().visibility(def_id.to_def_id()), self.level)
             {
-                self.ev.update(def_id, self.access_level);
+                self.ev.update(def_id, self.level);
             }
         }
         ControlFlow::CONTINUE
@@ -923,38 +911,39 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx>
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-/// Visitor, used for AccessLevels table checking
+/// Visitor, used for EffectiveVisibilities table checking
 ////////////////////////////////////////////////////////////////////////////////
 pub struct TestReachabilityVisitor<'tcx, 'a> {
     tcx: TyCtxt<'tcx>,
-    access_levels: &'a AccessLevels,
+    effective_visibilities: &'a EffectiveVisibilities,
 }
 
 impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
-    fn access_level_diagnostic(&mut self, def_id: LocalDefId) {
-        let span = self.tcx.def_span(def_id.to_def_id());
+    fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) {
         if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) {
             let mut error_msg = String::new();
-
-            let effective_vis =
-                self.access_levels.get_effective_vis(def_id).copied().unwrap_or_default();
-            for level in [
-                AccessLevel::Public,
-                AccessLevel::Exported,
-                AccessLevel::Reachable,
-                AccessLevel::ReachableFromImplTrait,
-            ] {
-                let vis_str = match effective_vis.get(level) {
-                    Some(ty::Visibility::Restricted(restricted_id)) => {
-                        format!("pub({})", self.tcx.item_name(restricted_id.to_def_id()))
+            let span = self.tcx.def_span(def_id.to_def_id());
+            if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) {
+                for level in Level::all_levels() {
+                    let vis_str = match effective_vis.at_level(level) {
+                        ty::Visibility::Restricted(restricted_id) => {
+                            if restricted_id.is_top_level_module() {
+                                "pub(crate)".to_string()
+                            } else if *restricted_id == self.tcx.parent_module_from_def_id(def_id) {
+                                "pub(self)".to_string()
+                            } else {
+                                format!("pub({})", self.tcx.item_name(restricted_id.to_def_id()))
+                            }
+                        }
+                        ty::Visibility::Public => "pub".to_string(),
+                    };
+                    if level != Level::Direct {
+                        error_msg.push_str(", ");
                     }
-                    Some(ty::Visibility::Public) => "pub".to_string(),
-                    None => "pub(self)".to_string(),
-                };
-                if level != AccessLevel::Public {
-                    error_msg.push_str(", ");
+                    error_msg.push_str(&format!("{:?}: {}", level, vis_str));
                 }
-                error_msg.push_str(&format!("{:?}: {}", level, vis_str));
+            } else {
+                error_msg.push_str("not in the table");
             }
             self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg });
         }
@@ -963,23 +952,23 @@ impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
 
 impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        self.access_level_diagnostic(item.def_id.def_id);
+        self.effective_visibility_diagnostic(item.owner_id.def_id);
 
         match item.kind {
             hir::ItemKind::Enum(ref def, _) => {
                 for variant in def.variants.iter() {
                     let variant_id = self.tcx.hir().local_def_id(variant.id);
-                    self.access_level_diagnostic(variant_id);
+                    self.effective_visibility_diagnostic(variant_id);
                     for field in variant.data.fields() {
                         let def_id = self.tcx.hir().local_def_id(field.hir_id);
-                        self.access_level_diagnostic(def_id);
+                        self.effective_visibility_diagnostic(def_id);
                     }
                 }
             }
             hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
                 for field in def.fields() {
                     let def_id = self.tcx.hir().local_def_id(field.hir_id);
-                    self.access_level_diagnostic(def_id);
+                    self.effective_visibility_diagnostic(def_id);
                 }
             }
             _ => {}
@@ -987,13 +976,13 @@ impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> {
     }
 
     fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) {
-        self.access_level_diagnostic(item.def_id.def_id);
+        self.effective_visibility_diagnostic(item.owner_id.def_id);
     }
     fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) {
-        self.access_level_diagnostic(item.def_id.def_id);
+        self.effective_visibility_diagnostic(item.owner_id.def_id);
     }
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
-        self.access_level_diagnostic(item.def_id.def_id);
+        self.effective_visibility_diagnostic(item.owner_id.def_id);
     }
 }
 
@@ -1064,7 +1053,7 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
 
     fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
         // Don't visit nested modules, since we run a separate visitor walk
-        // for each module in `privacy_access_levels`
+        // for each module in `effective_visibilities`
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
@@ -1076,7 +1065,7 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let orig_current_item = mem::replace(&mut self.current_item, item.def_id.def_id);
+        let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id);
         intravisit::walk_item(self, item);
         self.current_item = orig_current_item;
     }
@@ -1189,7 +1178,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
 
     fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
         // Don't visit nested modules, since we run a separate visitor walk
-        // for each module in `privacy_access_levels`
+        // for each module in `effective_visibilities`
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
@@ -1379,7 +1368,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
 
     // Check types in item interfaces.
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let orig_current_item = mem::replace(&mut self.current_item, item.def_id.def_id);
+        let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id);
         let old_maybe_typeck_results = self.maybe_typeck_results.take();
         intravisit::walk_item(self, item);
         self.maybe_typeck_results = old_maybe_typeck_results;
@@ -1414,7 +1403,7 @@ impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
 
 struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    access_levels: &'a AccessLevels,
+    effective_visibilities: &'a EffectiveVisibilities,
     in_variant: bool,
     // Set of errors produced by this obsolete visitor.
     old_error_set: HirIdSet,
@@ -1457,7 +1446,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     fn trait_is_public(&self, trait_id: LocalDefId) -> bool {
         // FIXME: this would preferably be using `exported_items`, but all
         // traits are exported currently (see `EmbargoVisitor.exported_trait`).
-        self.access_levels.is_public(trait_id)
+        self.effective_visibilities.is_directly_public(trait_id)
     }
 
     fn check_generic_bound(&mut self, bound: &hir::GenericBound<'_>) {
@@ -1469,7 +1458,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     }
 
     fn item_is_public(&self, def_id: LocalDefId) -> bool {
-        self.access_levels.is_reachable(def_id) || self.tcx.visibility(def_id).is_public()
+        self.effective_visibilities.is_reachable(def_id) || self.tcx.visibility(def_id).is_public()
     }
 }
 
@@ -1523,7 +1512,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
             hir::ItemKind::ForeignMod { .. } => {}
 
             hir::ItemKind::Trait(.., bounds, _) => {
-                if !self.trait_is_public(item.def_id.def_id) {
+                if !self.trait_is_public(item.owner_id.def_id) {
                     return;
                 }
 
@@ -1583,9 +1572,9 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
                     || impl_.items.iter().any(|impl_item_ref| {
                         let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                         match impl_item.kind {
-                            hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => {
-                                self.access_levels.is_reachable(impl_item_ref.id.def_id.def_id)
-                            }
+                            hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => self
+                                .effective_visibilities
+                                .is_reachable(impl_item_ref.id.owner_id.def_id),
                             hir::ImplItemKind::Type(_) => false,
                         }
                     });
@@ -1604,7 +1593,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
                                 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                                 match impl_item.kind {
                                     hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..)
-                                        if self.item_is_public(impl_item.def_id.def_id) =>
+                                        if self.item_is_public(impl_item.owner_id.def_id) =>
                                     {
                                         intravisit::walk_impl_item(self, impl_item)
                                     }
@@ -1645,8 +1634,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
                     // methods will be visible as `Public::foo`.
                     let mut found_pub_static = false;
                     for impl_item_ref in impl_.items {
-                        if self.access_levels.is_reachable(impl_item_ref.id.def_id.def_id)
-                            || self.tcx.visibility(impl_item_ref.id.def_id).is_public()
+                        if self
+                            .effective_visibilities
+                            .is_reachable(impl_item_ref.id.owner_id.def_id)
+                            || self.tcx.visibility(impl_item_ref.id.owner_id).is_public()
                         {
                             let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                             match impl_item_ref.kind {
@@ -1674,7 +1665,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
             hir::ItemKind::TyAlias(..) => return,
 
             // Not at all public, so we don't care.
-            _ if !self.item_is_public(item.def_id.def_id) => {
+            _ if !self.item_is_public(item.owner_id.def_id) => {
                 return;
             }
 
@@ -1705,7 +1696,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     }
 
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
-        if self.access_levels.is_reachable(item.def_id.def_id) {
+        if self.effective_visibilities.is_reachable(item.owner_id.def_id) {
             intravisit::walk_foreign_item(self, item)
         }
     }
@@ -1720,7 +1711,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     }
 
     fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
-        if self.access_levels.is_reachable(self.tcx.hir().local_def_id(v.id)) {
+        if self.effective_visibilities.is_reachable(self.tcx.hir().local_def_id(v.id)) {
             self.in_variant = true;
             intravisit::walk_variant(self, v);
             self.in_variant = false;
@@ -1942,7 +1933,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
 
     pub fn check_item(&mut self, id: ItemId) {
         let tcx = self.tcx;
-        let def_id = id.def_id.def_id;
+        let def_id = id.owner_id.def_id;
         let item_visibility = tcx.local_visibility(def_id);
         let def_kind = tcx.def_kind(def_id);
 
@@ -1958,17 +1949,17 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
             DefKind::Trait => {
                 let item = tcx.hir().item(id);
                 if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind {
-                    self.check(item.def_id.def_id, item_visibility).generics().predicates();
+                    self.check(item.owner_id.def_id, item_visibility).generics().predicates();
 
                     for trait_item_ref in trait_item_refs {
                         self.check_assoc_item(
-                            trait_item_ref.id.def_id.def_id,
+                            trait_item_ref.id.owner_id.def_id,
                             trait_item_ref.kind,
                             item_visibility,
                         );
 
                         if let AssocItemKind::Type = trait_item_ref.kind {
-                            self.check(trait_item_ref.id.def_id.def_id, item_visibility).bounds();
+                            self.check(trait_item_ref.id.owner_id.def_id, item_visibility).bounds();
                         }
                     }
                 }
@@ -1979,7 +1970,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
             DefKind::Enum => {
                 let item = tcx.hir().item(id);
                 if let hir::ItemKind::Enum(ref def, _) = item.kind {
-                    self.check(item.def_id.def_id, item_visibility).generics().predicates();
+                    self.check(item.owner_id.def_id, item_visibility).generics().predicates();
 
                     for variant in def.variants {
                         for field in variant.data.fields() {
@@ -1994,8 +1985,11 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                 let item = tcx.hir().item(id);
                 if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
                     for foreign_item in items {
-                        let vis = tcx.local_visibility(foreign_item.id.def_id.def_id);
-                        self.check(foreign_item.id.def_id.def_id, vis).generics().predicates().ty();
+                        let vis = tcx.local_visibility(foreign_item.id.owner_id.def_id);
+                        self.check(foreign_item.id.owner_id.def_id, vis)
+                            .generics()
+                            .predicates()
+                            .ty();
                     }
                 }
             }
@@ -2005,7 +1999,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                 if let hir::ItemKind::Struct(ref struct_def, _)
                 | hir::ItemKind::Union(ref struct_def, _) = item.kind
                 {
-                    self.check(item.def_id.def_id, item_visibility).generics().predicates();
+                    self.check(item.owner_id.def_id, item_visibility).generics().predicates();
 
                     for field in struct_def.fields() {
                         let def_id = tcx.hir().local_def_id(field.hir_id);
@@ -2022,20 +2016,24 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                 let item = tcx.hir().item(id);
                 if let hir::ItemKind::Impl(ref impl_) = item.kind {
                     let impl_vis =
-                        ty::Visibility::of_impl(item.def_id.def_id, tcx, &Default::default());
+                        ty::Visibility::of_impl(item.owner_id.def_id, tcx, &Default::default());
                     // check that private components do not appear in the generics or predicates of inherent impls
                     // this check is intentionally NOT performed for impls of traits, per #90586
                     if impl_.of_trait.is_none() {
-                        self.check(item.def_id.def_id, impl_vis).generics().predicates();
+                        self.check(item.owner_id.def_id, impl_vis).generics().predicates();
                     }
                     for impl_item_ref in impl_.items {
                         let impl_item_vis = if impl_.of_trait.is_none() {
-                            min(tcx.local_visibility(impl_item_ref.id.def_id.def_id), impl_vis, tcx)
+                            min(
+                                tcx.local_visibility(impl_item_ref.id.owner_id.def_id),
+                                impl_vis,
+                                tcx,
+                            )
                         } else {
                             impl_vis
                         };
                         self.check_assoc_item(
-                            impl_item_ref.id.def_id.def_id,
+                            impl_item_ref.id.owner_id.def_id,
                             impl_item_ref.kind,
                             impl_item_vis,
                         );
@@ -2050,7 +2048,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         visibility,
-        privacy_access_levels,
+        effective_visibilities,
         check_private_in_public,
         check_mod_privacy,
         ..*providers
@@ -2122,14 +2120,14 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     intravisit::walk_mod(&mut visitor, module, hir_id);
 }
 
-fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels {
+fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
     // Build up a set of all exported items in the AST. This is a set of all
     // items which are reachable from external crates based on visibility.
     let mut visitor = EmbargoVisitor {
         tcx,
-        access_levels: tcx.resolutions(()).access_levels.clone(),
+        effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
         macro_reachable: Default::default(),
-        prev_level: Some(AccessLevel::Public),
+        prev_level: Some(Level::Direct),
         changed: false,
     };
 
@@ -2142,18 +2140,19 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels {
         }
     }
 
-    let mut check_visitor = TestReachabilityVisitor { tcx, access_levels: &visitor.access_levels };
+    let mut check_visitor =
+        TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities };
     tcx.hir().visit_all_item_likes_in_crate(&mut check_visitor);
 
-    tcx.arena.alloc(visitor.access_levels)
+    tcx.arena.alloc(visitor.effective_visibilities)
 }
 
 fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
-    let access_levels = tcx.privacy_access_levels(());
+    let effective_visibilities = tcx.effective_visibilities(());
 
     let mut visitor = ObsoleteVisiblePrivateTypesVisitor {
         tcx,
-        access_levels,
+        effective_visibilities,
         in_variant: false,
         old_error_set: Default::default(),
     };
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index e7f12caaf33..b2111a1262a 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -21,7 +21,7 @@ rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
 tracing = "0.1"
 
 [features]
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 8e018d3e4a4..11d4c97e71c 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -22,8 +22,7 @@ use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::{self, DepKindStruct};
 use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values};
 use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine};
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::def_id::{LocalDefId, LOCAL_CRATE};
+use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
 
 #[macro_use]
@@ -45,14 +44,6 @@ pub use on_disk_cache::OnDiskCache;
 mod profiling_support;
 pub use self::profiling_support::alloc_self_profile_query_strings;
 
-fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
-    if def_id.is_top_level_module() {
-        "top-level module".to_string()
-    } else {
-        format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
-    }
-}
-
 rustc_query_append! { define_queries! }
 
 impl<'tcx> Queries<'tcx> {
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index e96ea682cae..8b14ce210a2 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -1,8 +1,9 @@
 use crate::QueryCtxt;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock};
 use rustc_data_structures::unhash::UnhashMap;
+use rustc_data_structures::unord::UnordSet;
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathHash;
 use rustc_index::vec::{Idx, IndexVec};
@@ -792,7 +793,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
     }
 }
 
-impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId> {
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId> {
     fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
         RefDecodable::decode(d)
     }
@@ -848,6 +849,7 @@ impl_ref_decoder! {<'tcx>
     rustc_span::def_id::DefId,
     rustc_span::def_id::LocalDefId,
     (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo),
+    ty::DeducedParamAttrs,
 }
 
 //- ENCODING -------------------------------------------------------------------
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index aaeaa3bd51d..1d17f422196 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -298,7 +298,7 @@ pub(crate) fn create_query_frame<
     K: Copy + Key + for<'a> HashStable<StableHashingContext<'a>>,
 >(
     tcx: QueryCtxt<'tcx>,
-    do_describe: fn(QueryCtxt<'tcx>, K) -> String,
+    do_describe: fn(TyCtxt<'tcx>, K) -> String,
     key: K,
     kind: DepKind,
     name: &'static str,
@@ -307,7 +307,7 @@ pub(crate) fn create_query_frame<
     // Showing visible path instead of any path is not that important in production.
     let description = ty::print::with_no_visible_paths!(
         // Force filename-line mode to avoid invoking `type_of` query.
-        ty::print::with_forced_impl_filename_line!(do_describe(tcx, key))
+        ty::print::with_forced_impl_filename_line!(do_describe(tcx.tcx, key))
     );
     let description =
         if tcx.sess.verbose() { format!("{} [{}]", description, name) } else { description };
@@ -466,7 +466,10 @@ macro_rules! define_queries {
         }
 
         impl<'tcx> QueryDescription<QueryCtxt<'tcx>> for queries::$name<'tcx> {
-            rustc_query_description! { $name }
+            #[inline]
+            fn cache_on_disk(tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool {
+                ::rustc_middle::query::cached::$name(tcx, key)
+            }
 
             type Cache = query_storage::$name<'tcx>;
 
@@ -576,7 +579,7 @@ macro_rules! define_queries {
             use rustc_middle::ty::TyCtxt;
             use $crate::plumbing::{QueryStruct, QueryCtxt};
             use $crate::profiling_support::QueryKeyStringCache;
-            use rustc_query_system::query::{QueryDescription, QueryMap};
+            use rustc_query_system::query::QueryMap;
 
             pub(super) const fn dummy_query_struct<'tcx>() -> QueryStruct<'tcx> {
                 fn noop_try_collect_active_jobs(_: QueryCtxt<'_>, _: &mut QueryMap) -> Option<()> {
@@ -603,7 +606,7 @@ macro_rules! define_queries {
                     let make_query = |tcx, key| {
                         let kind = rustc_middle::dep_graph::DepKind::$name;
                         let name = stringify!($name);
-                        $crate::plumbing::create_query_frame(tcx, super::queries::$name::describe, key, kind, name)
+                        $crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name)
                     };
                     tcx.queries.$name.try_collect_active_jobs(
                         tcx,
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index faddad74171..028756b5a0a 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -22,7 +22,7 @@ rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 rustc_type_ir = { path = "../rustc_type_ir" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
 tracing = "0.1"
 
 [features]
diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs
index 1e74e0e2990..7a20eaceba0 100644
--- a/compiler/rustc_query_system/src/error.rs
+++ b/compiler/rustc_query_system/src/error.rs
@@ -3,7 +3,7 @@ use rustc_session::Limit;
 use rustc_span::{Span, Symbol};
 
 #[derive(Subdiagnostic)]
-#[note(query_system::cycle_stack_middle)]
+#[note(query_system_cycle_stack_middle)]
 pub struct CycleStack {
     #[primary_span]
     pub span: Span,
@@ -19,24 +19,24 @@ pub enum HandleCycleError {
 
 #[derive(Subdiagnostic)]
 pub enum StackCount {
-    #[note(query_system::cycle_stack_single)]
+    #[note(query_system_cycle_stack_single)]
     Single,
-    #[note(query_system::cycle_stack_multiple)]
+    #[note(query_system_cycle_stack_multiple)]
     Multiple,
 }
 
 #[derive(Subdiagnostic)]
 pub enum Alias {
-    #[note(query_system::cycle_recursive_ty_alias)]
-    #[help(query_system::cycle_recursive_ty_alias_help1)]
-    #[help(query_system::cycle_recursive_ty_alias_help2)]
+    #[note(query_system_cycle_recursive_ty_alias)]
+    #[help(query_system_cycle_recursive_ty_alias_help1)]
+    #[help(query_system_cycle_recursive_ty_alias_help2)]
     Ty,
-    #[note(query_system::cycle_recursive_trait_alias)]
+    #[note(query_system_cycle_recursive_trait_alias)]
     Trait,
 }
 
 #[derive(Subdiagnostic)]
-#[note(query_system::cycle_usage)]
+#[note(query_system_cycle_usage)]
 pub struct CycleUsage {
     #[primary_span]
     pub span: Span,
@@ -44,7 +44,7 @@ pub struct CycleUsage {
 }
 
 #[derive(Diagnostic)]
-#[diag(query_system::cycle, code = "E0391")]
+#[diag(query_system_cycle, code = "E0391")]
 pub struct Cycle {
     #[primary_span]
     pub span: Span,
@@ -60,14 +60,14 @@ pub struct Cycle {
 }
 
 #[derive(Diagnostic)]
-#[diag(query_system::reentrant)]
+#[diag(query_system_reentrant)]
 pub struct Reentrant;
 
 #[derive(Diagnostic)]
-#[diag(query_system::increment_compilation)]
+#[diag(query_system_increment_compilation)]
 #[help]
-#[note(query_system::increment_compilation_note1)]
-#[note(query_system::increment_compilation_note2)]
+#[note(query_system_increment_compilation_note1)]
+#[note(query_system_increment_compilation_note2)]
 pub struct IncrementCompilation {
     pub run_cmd: String,
     pub dep_node: String,
@@ -75,7 +75,7 @@ pub struct IncrementCompilation {
 
 #[derive(Diagnostic)]
 #[help]
-#[diag(query_system::query_overflow)]
+#[diag(query_system_query_overflow)]
 pub struct QueryOverflow {
     #[primary_span]
     pub span: Option<Span>,
@@ -86,7 +86,7 @@ pub struct QueryOverflow {
 }
 
 #[derive(Subdiagnostic)]
-#[note(query_system::layout_of_depth)]
+#[note(query_system_layout_of_depth)]
 pub struct LayoutOfDepth {
     pub desc: String,
     pub depth: usize,
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index c4549cc9eb4..0a1cffa3b33 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -49,8 +49,6 @@ impl<CTX: QueryContext, K, V> QueryVTable<CTX, K, V> {
 pub trait QueryDescription<CTX: QueryContext>: QueryConfig {
     type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>;
 
-    fn describe(tcx: CTX, key: Self::Key) -> String;
-
     // Don't use this method to access query results, instead use the methods on TyCtxt
     fn query_state<'a>(tcx: CTX) -> &'a QueryState<Self::Key>
     where
diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs
deleted file mode 100644
index d806441716f..00000000000
--- a/compiler/rustc_resolve/src/access_levels.rs
+++ /dev/null
@@ -1,180 +0,0 @@
-use crate::NameBinding;
-use crate::NameBindingKind;
-use crate::Resolver;
-use rustc_ast::ast;
-use rustc_ast::visit;
-use rustc_ast::visit::Visitor;
-use rustc_ast::Crate;
-use rustc_ast::EnumDef;
-use rustc_ast::NodeId;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_middle::middle::privacy::AccessLevel;
-use rustc_middle::ty::DefIdTree;
-use rustc_span::sym;
-
-pub struct AccessLevelsVisitor<'r, 'a> {
-    r: &'r mut Resolver<'a>,
-    changed: bool,
-}
-
-impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
-    /// Fills the `Resolver::access_levels` table with public & exported items
-    /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
-    /// need access to a TyCtxt for that.
-    pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
-        let mut visitor = AccessLevelsVisitor { r, changed: false };
-
-        visitor.set_access_level_def_id(CRATE_DEF_ID, Some(AccessLevel::Public));
-        visitor.set_bindings_access_level(CRATE_DEF_ID);
-
-        while visitor.changed {
-            visitor.reset();
-            visit::walk_crate(&mut visitor, krate);
-        }
-
-        info!("resolve::access_levels: {:#?}", r.access_levels);
-    }
-
-    fn reset(&mut self) {
-        self.changed = false;
-    }
-
-    /// Update the access level of the bindings in the given module accordingly. The module access
-    /// level has to be Exported or Public.
-    /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
-    fn set_bindings_access_level(&mut self, module_id: LocalDefId) {
-        assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
-        let module_level = self.r.access_levels.get_access_level(module_id);
-        if !module_level.is_some() {
-            return;
-        }
-        // Set the given binding access level to `AccessLevel::Public` and
-        // sets the rest of the `use` chain to `AccessLevel::Exported` until
-        // we hit the actual exported item.
-        let set_import_binding_access_level =
-            |this: &mut Self, mut binding: &NameBinding<'a>, mut access_level, ns| {
-                while let NameBindingKind::Import { binding: nested_binding, import, .. } =
-                    binding.kind
-                {
-                    this.set_access_level(this.r.import_id_for_ns(import, ns), access_level);
-
-                    access_level = Some(AccessLevel::Exported);
-                    binding = nested_binding;
-                }
-            };
-
-        let module = self.r.get_module(module_id.to_def_id()).unwrap();
-        let resolutions = self.r.resolutions(module);
-
-        for (key, name_resolution) in resolutions.borrow().iter() {
-            if let Some(binding) = name_resolution.borrow().binding() && binding.vis.is_public() && !binding.is_ambiguity() {
-                let access_level = match binding.is_import() {
-                    true => {
-                        set_import_binding_access_level(self, binding, module_level, key.ns);
-                        Some(AccessLevel::Exported)
-                    },
-                    false => module_level,
-                };
-                if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
-                    self.set_access_level_def_id(def_id, access_level);
-                }
-            }
-        }
-    }
-
-    /// Sets the access level of the `LocalDefId` corresponding to the given `NodeId`.
-    /// This function will panic if the `NodeId` does not have a `LocalDefId`
-    fn set_access_level(
-        &mut self,
-        node_id: NodeId,
-        access_level: Option<AccessLevel>,
-    ) -> Option<AccessLevel> {
-        self.set_access_level_def_id(self.r.local_def_id(node_id), access_level)
-    }
-
-    fn set_access_level_def_id(
-        &mut self,
-        def_id: LocalDefId,
-        access_level: Option<AccessLevel>,
-    ) -> Option<AccessLevel> {
-        let old_level = self.r.access_levels.get_access_level(def_id);
-        if old_level < access_level {
-            self.r.access_levels.set_access_level(def_id, access_level.unwrap());
-            self.changed = true;
-            access_level
-        } else {
-            old_level
-        }
-    }
-}
-
-impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
-    fn visit_item(&mut self, item: &'ast ast::Item) {
-        let def_id = self.r.local_def_id(item.id);
-        // Set access level of nested items.
-        // If it's a mod, also make the visitor walk all of its items
-        match item.kind {
-            // Resolved in rustc_privacy when types are available
-            ast::ItemKind::Impl(..) => return,
-
-            // Should be unreachable at this stage
-            ast::ItemKind::MacCall(..) => panic!(
-                "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
-            ),
-
-            // Foreign modules inherit level from parents.
-            ast::ItemKind::ForeignMod(..) => {
-                let parent_level =
-                    self.r.access_levels.get_access_level(self.r.local_parent(def_id));
-                self.set_access_level(item.id, parent_level);
-            }
-
-            // Only exported `macro_rules!` items are public, but they always are
-            ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
-                if item.attrs.iter().any(|attr| attr.has_name(sym::macro_export)) {
-                    self.set_access_level(item.id, Some(AccessLevel::Public));
-                }
-            }
-
-            ast::ItemKind::Mod(..) => {
-                self.set_bindings_access_level(def_id);
-                visit::walk_item(self, item);
-            }
-
-            ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
-                self.set_bindings_access_level(def_id);
-                for variant in variants {
-                    let variant_def_id = self.r.local_def_id(variant.id);
-                    let variant_level = self.r.access_levels.get_access_level(variant_def_id);
-                    for field in variant.data.fields() {
-                        self.set_access_level(field.id, variant_level);
-                    }
-                }
-            }
-
-            ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
-                let inherited_level = self.r.access_levels.get_access_level(def_id);
-                for field in def.fields() {
-                    if field.vis.kind.is_pub() {
-                        self.set_access_level(field.id, inherited_level);
-                    }
-                }
-            }
-
-            ast::ItemKind::Trait(..) => {
-                self.set_bindings_access_level(def_id);
-            }
-
-            ast::ItemKind::ExternCrate(..)
-            | ast::ItemKind::Use(..)
-            | ast::ItemKind::Static(..)
-            | ast::ItemKind::Const(..)
-            | ast::ItemKind::GlobalAsm(..)
-            | ast::ItemKind::TyAlias(..)
-            | ast::ItemKind::TraitAlias(..)
-            | ast::ItemKind::MacroDef(..)
-            | ast::ItemKind::Fn(..) => return,
-        }
-    }
-}
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index a17793ecd99..423c5727533 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -56,21 +56,7 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a>
 impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span, LocalExpnId) {
     fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
         arenas.alloc_name_binding(NameBinding {
-            kind: NameBindingKind::Res(self.0, false),
-            ambiguity: None,
-            vis: self.1.to_def_id(),
-            span: self.2,
-            expansion: self.3,
-        })
-    }
-}
-
-struct IsMacroExport;
-
-impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId, IsMacroExport) {
-    fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
-        arenas.alloc_name_binding(NameBinding {
-            kind: NameBindingKind::Res(self.0, true),
+            kind: NameBindingKind::Res(self.0),
             ambiguity: None,
             vis: self.1.to_def_id(),
             span: self.2,
@@ -364,7 +350,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         module_path: Vec<Segment>,
         kind: ImportKind<'a>,
         span: Span,
-        id: NodeId,
         item: &ast::Item,
         root_span: Span,
         root_id: NodeId,
@@ -377,7 +362,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
             module_path,
             imported_module: Cell::new(None),
             span,
-            id,
             use_span: item.span,
             use_span_with_attributes: item.span_with_attributes(),
             has_attributes: !item.attrs.is_empty(),
@@ -574,27 +558,20 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                     },
                     type_ns_only,
                     nested,
+                    id,
                     additional_ids: (id1, id2),
                 };
 
-                self.add_import(
-                    module_path,
-                    kind,
-                    use_tree.span,
-                    id,
-                    item,
-                    root_span,
-                    item.id,
-                    vis,
-                );
+                self.add_import(module_path, kind, use_tree.span, item, root_span, item.id, vis);
             }
             ast::UseTreeKind::Glob => {
                 let kind = ImportKind::Glob {
                     is_prelude: self.r.session.contains_name(&item.attrs, sym::prelude_import),
                     max_vis: Cell::new(None),
+                    id,
                 };
                 self.r.visibilities.insert(self.r.local_def_id(id), vis);
-                self.add_import(prefix, kind, use_tree.span, id, item, root_span, item.id, vis);
+                self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis);
             }
             ast::UseTreeKind::Nested(ref items) => {
                 // Ensure there is at most one `self` in the list
@@ -881,9 +858,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         })
         .unwrap_or((true, None, self.r.dummy_binding));
         let import = self.r.arenas.alloc_import(Import {
-            kind: ImportKind::ExternCrate { source: orig_name, target: ident },
+            kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id },
             root_id: item.id,
-            id: item.id,
             parent_scope: self.parent_scope,
             imported_module: Cell::new(module),
             has_attributes: !item.attrs.is_empty(),
@@ -1118,7 +1094,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
             this.r.arenas.alloc_import(Import {
                 kind: ImportKind::MacroUse,
                 root_id: item.id,
-                id: item.id,
                 parent_scope: this.parent_scope,
                 imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
                 use_span_with_attributes: item.span_with_attributes(),
@@ -1278,8 +1253,22 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
             let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
             self.r.set_binding_parent_module(binding, parent_scope.module);
             if is_macro_export {
-                let module = self.r.graph_root;
-                self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport));
+                let import = self.r.arenas.alloc_import(Import {
+                    kind: ImportKind::MacroExport,
+                    root_id: item.id,
+                    parent_scope: self.parent_scope,
+                    imported_module: Cell::new(None),
+                    has_attributes: false,
+                    use_span_with_attributes: span,
+                    use_span: span,
+                    root_span: span,
+                    span: span,
+                    module_path: Vec::new(),
+                    vis: Cell::new(Some(vis)),
+                    used: Cell::new(true),
+                });
+                let import_binding = self.r.import(binding, import);
+                self.r.define(self.r.graph_root, ident, MacroNS, import_binding);
             } else {
                 self.r.check_reserved_macro_name(ident, res);
                 self.insert_unused_macro(ident, def_id, item.id, &rule_spans);
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 01c3801f223..32fb5e18276 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -234,7 +234,7 @@ impl Resolver<'_> {
                         if !import.span.is_dummy() {
                             self.lint_buffer.buffer_lint(
                                 MACRO_USE_EXTERN_CRATE,
-                                import.id,
+                                import.root_id,
                                 import.span,
                                 "deprecated `#[macro_use]` attribute used to \
                                 import macros should be replaced at use sites \
@@ -244,13 +244,13 @@ impl Resolver<'_> {
                         }
                     }
                 }
-                ImportKind::ExternCrate { .. } => {
-                    let def_id = self.local_def_id(import.id);
+                ImportKind::ExternCrate { id, .. } => {
+                    let def_id = self.local_def_id(id);
                     self.maybe_unused_extern_crates.push((def_id, import.span));
                 }
                 ImportKind::MacroUse => {
                     let msg = "unused `#[macro_use]` import";
-                    self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg);
+                    self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.root_id, import.span, msg);
                 }
                 _ => {}
             }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index c4644d4f076..7961e3f1194 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -24,7 +24,7 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::{BytePos, Span, SyntaxContext};
 
 use crate::imports::{Import, ImportKind, ImportResolver};
 use crate::late::{PatternSource, Rib};
@@ -47,6 +47,7 @@ pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
 /// similarly named label and whether or not it is reachable.
 pub(crate) type LabelSuggestion = (Ident, bool);
 
+#[derive(Debug)]
 pub(crate) enum SuggestionTarget {
     /// The target has a similar name as the name used by the programmer (probably a typo)
     SimilarlyNamed,
@@ -54,18 +55,35 @@ pub(crate) enum SuggestionTarget {
     SingleItem,
 }
 
+#[derive(Debug)]
 pub(crate) struct TypoSuggestion {
     pub candidate: Symbol,
+    /// The source location where the name is defined; None if the name is not defined
+    /// in source e.g. primitives
+    pub span: Option<Span>,
     pub res: Res,
     pub target: SuggestionTarget,
 }
 
 impl TypoSuggestion {
-    pub(crate) fn typo_from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
-        Self { candidate, res, target: SuggestionTarget::SimilarlyNamed }
+    pub(crate) fn typo_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
+        Self {
+            candidate: ident.name,
+            span: Some(ident.span),
+            res,
+            target: SuggestionTarget::SimilarlyNamed,
+        }
+    }
+    pub(crate) fn typo_from_name(candidate: Symbol, res: Res) -> TypoSuggestion {
+        Self { candidate, span: None, res, target: SuggestionTarget::SimilarlyNamed }
     }
-    pub(crate) fn single_item_from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
-        Self { candidate, res, target: SuggestionTarget::SingleItem }
+    pub(crate) fn single_item_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
+        Self {
+            candidate: ident.name,
+            span: Some(ident.span),
+            res,
+            target: SuggestionTarget::SingleItem,
+        }
     }
 }
 
@@ -172,12 +190,12 @@ impl<'a> Resolver<'a> {
             ModuleKind::Block => "block",
         };
 
-        let old_noun = match old_binding.is_import() {
+        let old_noun = match old_binding.is_import_user_facing() {
             true => "import",
             false => "definition",
         };
 
-        let new_participle = match new_binding.is_import() {
+        let new_participle = match new_binding.is_import_user_facing() {
             true => "imported",
             false => "defined",
         };
@@ -208,7 +226,7 @@ impl<'a> Resolver<'a> {
                 true => struct_span_err!(self.session, span, E0254, "{}", msg),
                 false => struct_span_err!(self.session, span, E0260, "{}", msg),
             },
-            _ => match (old_binding.is_import(), new_binding.is_import()) {
+            _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) {
                 (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg),
                 (true, true) => struct_span_err!(self.session, span, E0252, "{}", msg),
                 _ => struct_span_err!(self.session, span, E0255, "{}", msg),
@@ -230,14 +248,18 @@ impl<'a> Resolver<'a> {
 
         // See https://github.com/rust-lang/rust/issues/32354
         use NameBindingKind::Import;
+        let can_suggest = |binding: &NameBinding<'_>, import: &self::Import<'_>| {
+            !binding.span.is_dummy()
+                && !matches!(import.kind, ImportKind::MacroUse | ImportKind::MacroExport)
+        };
         let import = match (&new_binding.kind, &old_binding.kind) {
             // If there are two imports where one or both have attributes then prefer removing the
             // import without attributes.
             (Import { import: new, .. }, Import { import: old, .. })
                 if {
-                    !new_binding.span.is_dummy()
-                        && !old_binding.span.is_dummy()
-                        && (new.has_attributes || old.has_attributes)
+                    (new.has_attributes || old.has_attributes)
+                        && can_suggest(old_binding, old)
+                        && can_suggest(new_binding, new)
                 } =>
             {
                 if old.has_attributes {
@@ -247,10 +269,10 @@ impl<'a> Resolver<'a> {
                 }
             }
             // Otherwise prioritize the new binding.
-            (Import { import, .. }, other) if !new_binding.span.is_dummy() => {
+            (Import { import, .. }, other) if can_suggest(new_binding, import) => {
                 Some((import, new_binding.span, other.is_import()))
             }
-            (other, Import { import, .. }) if !old_binding.span.is_dummy() => {
+            (other, Import { import, .. }) if can_suggest(old_binding, import) => {
                 Some((import, old_binding.span, other.is_import()))
             }
             _ => None,
@@ -335,7 +357,7 @@ impl<'a> Resolver<'a> {
                     }
                 }
             }
-            ImportKind::ExternCrate { source, target } => {
+            ImportKind::ExternCrate { source, target, .. } => {
                 suggestion = Some(format!(
                     "extern crate {} as {};",
                     source.unwrap_or(target.name),
@@ -482,12 +504,13 @@ impl<'a> Resolver<'a> {
         module: Module<'a>,
         names: &mut Vec<TypoSuggestion>,
         filter_fn: &impl Fn(Res) -> bool,
+        ctxt: Option<SyntaxContext>,
     ) {
         for (key, resolution) in self.resolutions(module).borrow().iter() {
             if let Some(binding) = resolution.borrow().binding {
                 let res = binding.res();
-                if filter_fn(res) {
-                    names.push(TypoSuggestion::typo_from_res(key.ident.name, res));
+                if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) {
+                    names.push(TypoSuggestion::typo_from_ident(key.ident, res));
                 }
             }
         }
@@ -1142,7 +1165,7 @@ impl<'a> Resolver<'a> {
                                 .get(&expn_id)
                                 .into_iter()
                                 .flatten()
-                                .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)),
+                                .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
                         );
                     }
                 }
@@ -1161,7 +1184,7 @@ impl<'a> Resolver<'a> {
                                 suggestions.extend(
                                     ext.helper_attrs
                                         .iter()
-                                        .map(|name| TypoSuggestion::typo_from_res(*name, res)),
+                                        .map(|name| TypoSuggestion::typo_from_name(*name, res)),
                                 );
                             }
                         }
@@ -1171,8 +1194,8 @@ impl<'a> Resolver<'a> {
                     if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() {
                         let res = macro_rules_binding.binding.res();
                         if filter_fn(res) {
-                            suggestions.push(TypoSuggestion::typo_from_res(
-                                macro_rules_binding.ident.name,
+                            suggestions.push(TypoSuggestion::typo_from_ident(
+                                macro_rules_binding.ident,
                                 res,
                             ))
                         }
@@ -1181,16 +1204,16 @@ impl<'a> Resolver<'a> {
                 Scope::CrateRoot => {
                     let root_ident = Ident::new(kw::PathRoot, ident.span);
                     let root_module = this.resolve_crate_root(root_ident);
-                    this.add_module_candidates(root_module, &mut suggestions, filter_fn);
+                    this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
                 }
-                Scope::Module(module, _) => {
-                    this.add_module_candidates(module, &mut suggestions, filter_fn);
+                Scope::Module(module) => {
+                    this.add_module_candidates(module, &mut suggestions, filter_fn, None);
                 }
                 Scope::MacroUsePrelude => {
                     suggestions.extend(this.macro_use_prelude.iter().filter_map(
                         |(name, binding)| {
                             let res = binding.res();
-                            filter_fn(res).then_some(TypoSuggestion::typo_from_res(*name, res))
+                            filter_fn(res).then_some(TypoSuggestion::typo_from_name(*name, res))
                         },
                     ));
                 }
@@ -1200,14 +1223,14 @@ impl<'a> Resolver<'a> {
                         suggestions.extend(
                             BUILTIN_ATTRIBUTES
                                 .iter()
-                                .map(|attr| TypoSuggestion::typo_from_res(attr.name, res)),
+                                .map(|attr| TypoSuggestion::typo_from_name(attr.name, res)),
                         );
                     }
                 }
                 Scope::ExternPrelude => {
                     suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
                         let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
-                        filter_fn(res).then_some(TypoSuggestion::typo_from_res(ident.name, res))
+                        filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
                     }));
                 }
                 Scope::ToolPrelude => {
@@ -1215,13 +1238,13 @@ impl<'a> Resolver<'a> {
                     suggestions.extend(
                         this.registered_tools
                             .iter()
-                            .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)),
+                            .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
                     );
                 }
                 Scope::StdLibPrelude => {
                     if let Some(prelude) = this.prelude {
                         let mut tmp_suggestions = Vec::new();
-                        this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn);
+                        this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None);
                         suggestions.extend(
                             tmp_suggestions
                                 .into_iter()
@@ -1232,7 +1255,8 @@ impl<'a> Resolver<'a> {
                 Scope::BuiltinTypes => {
                     suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| {
                         let res = Res::PrimTy(*prim_ty);
-                        filter_fn(res).then_some(TypoSuggestion::typo_from_res(prim_ty.name(), res))
+                        filter_fn(res)
+                            .then_some(TypoSuggestion::typo_from_name(prim_ty.name(), res))
                     }))
                 }
             }
@@ -1663,7 +1687,7 @@ impl<'a> Resolver<'a> {
             let a = if built_in.is_empty() { res.article() } else { "a" };
             format!("{a}{built_in} {thing}{from}", thing = res.descr())
         } else {
-            let introduced = if b.is_import() { "imported" } else { "defined" };
+            let introduced = if b.is_import_user_facing() { "imported" } else { "defined" };
             format!("the {thing} {introduced} here", thing = res.descr())
         }
     }
@@ -1722,10 +1746,10 @@ impl<'a> Resolver<'a> {
     /// If the binding refers to a tuple struct constructor with fields,
     /// returns the span of its fields.
     fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option<Span> {
-        if let NameBindingKind::Res(
-            Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id),
-            _,
-        ) = binding.kind
+        if let NameBindingKind::Res(Res::Def(
+            DefKind::Ctor(CtorOf::Struct, CtorKind::Fn),
+            ctor_def_id,
+        )) = binding.kind
         {
             let def_id = self.parent(ctor_def_id);
             let fields = self.field_names.get(&def_id)?;
@@ -1769,7 +1793,9 @@ impl<'a> Resolver<'a> {
                         next_ident = source;
                         Some(binding)
                     }
-                    ImportKind::Glob { .. } | ImportKind::MacroUse => Some(binding),
+                    ImportKind::Glob { .. } | ImportKind::MacroUse | ImportKind::MacroExport => {
+                        Some(binding)
+                    }
                     ImportKind::ExternCrate { .. } => None,
                 },
                 _ => None,
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
new file mode 100644
index 00000000000..17ce854cb43
--- /dev/null
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -0,0 +1,200 @@
+use crate::{ImportKind, NameBindingKind, Resolver};
+use rustc_ast::ast;
+use rustc_ast::visit;
+use rustc_ast::visit::Visitor;
+use rustc_ast::Crate;
+use rustc_ast::EnumDef;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::CRATE_DEF_ID;
+use rustc_middle::middle::privacy::Level;
+use rustc_middle::ty::{DefIdTree, Visibility};
+
+pub struct EffectiveVisibilitiesVisitor<'r, 'a> {
+    r: &'r mut Resolver<'a>,
+    changed: bool,
+}
+
+impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
+    /// Fills the `Resolver::effective_visibilities` table with public & exported items
+    /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
+    /// need access to a TyCtxt for that.
+    pub fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
+        let mut visitor = EffectiveVisibilitiesVisitor { r, changed: false };
+
+        visitor.update(CRATE_DEF_ID, Visibility::Public, CRATE_DEF_ID, Level::Direct);
+        visitor.set_bindings_effective_visibilities(CRATE_DEF_ID);
+
+        while visitor.changed {
+            visitor.reset();
+            visit::walk_crate(&mut visitor, krate);
+        }
+
+        info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities);
+    }
+
+    fn reset(&mut self) {
+        self.changed = false;
+    }
+
+    /// Update effective visibilities of bindings in the given module,
+    /// including their whole reexport chains.
+    fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) {
+        assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
+        let module = self.r.get_module(module_id.to_def_id()).unwrap();
+        let resolutions = self.r.resolutions(module);
+
+        for (_, name_resolution) in resolutions.borrow().iter() {
+            if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() {
+                // Set the given effective visibility level to `Level::Direct` and
+                // sets the rest of the `use` chain to `Level::Reexported` until
+                // we hit the actual exported item.
+
+                // FIXME: tag and is_public() condition should be removed, but assertions occur.
+                let tag = if binding.is_import() { Level::Reexported } else { Level::Direct };
+                if binding.vis.is_public() {
+                    let mut prev_parent_id = module_id;
+                    let mut level = Level::Direct;
+                    while let NameBindingKind::Import { binding: nested_binding, import, .. } =
+                        binding.kind
+                    {
+                        let mut update = |node_id| {
+                            self.update(
+                                self.r.local_def_id(node_id),
+                                binding.vis.expect_local(),
+                                prev_parent_id,
+                                level,
+                            )
+                        };
+                        match import.kind {
+                            ImportKind::Single { id, additional_ids, .. } => {
+                                // In theory all the import IDs have individual visibilities and
+                                // effective visibilities, but in practice these IDs go straigth to
+                                // HIR where all their few uses assume that their (effective)
+                                // visibility applies to the whole syntactic `use` item. So we
+                                // update them all to the maximum value among the potential
+                                // individual effective visibilities. Maybe HIR for imports
+                                // shouldn't use three IDs at all.
+                                update(id);
+                                update(additional_ids.0);
+                                update(additional_ids.1);
+                                prev_parent_id = self.r.local_def_id(id);
+                            }
+                            ImportKind::Glob { id, .. } | ImportKind::ExternCrate { id, .. } => {
+                                update(id);
+                                prev_parent_id = self.r.local_def_id(id);
+                            }
+                            ImportKind::MacroUse => {
+                                // In theory we should reset the parent id to something private
+                                // here, but `macro_use` imports always refer to external items,
+                                // so it doesn't matter and we can just do nothing.
+                            }
+                            ImportKind::MacroExport => {
+                                // In theory we should reset the parent id to something public
+                                // here, but it has the same effect as leaving the previous parent,
+                                // so we can just do nothing.
+                            }
+                        }
+
+                        level = Level::Reexported;
+                        binding = nested_binding;
+                    }
+                }
+
+                if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
+                    self.update(def_id, binding.vis.expect_local(), module_id, tag);
+                }
+            }
+        }
+    }
+
+    fn update(
+        &mut self,
+        def_id: LocalDefId,
+        nominal_vis: Visibility,
+        parent_id: LocalDefId,
+        tag: Level,
+    ) {
+        let module_id = self
+            .r
+            .get_nearest_non_block_module(def_id.to_def_id())
+            .nearest_parent_mod()
+            .expect_local();
+        if nominal_vis == Visibility::Restricted(module_id)
+            || self.r.visibilities[&parent_id] == Visibility::Restricted(module_id)
+        {
+            return;
+        }
+        let mut effective_visibilities = std::mem::take(&mut self.r.effective_visibilities);
+        self.changed |= effective_visibilities.update(
+            def_id,
+            nominal_vis,
+            || Visibility::Restricted(module_id),
+            parent_id,
+            tag,
+            &*self.r,
+        );
+        self.r.effective_visibilities = effective_visibilities;
+    }
+}
+
+impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
+    fn visit_item(&mut self, item: &'ast ast::Item) {
+        let def_id = self.r.local_def_id(item.id);
+        // Update effective visibilities of nested items.
+        // If it's a mod, also make the visitor walk all of its items
+        match item.kind {
+            // Resolved in rustc_privacy when types are available
+            ast::ItemKind::Impl(..) => return,
+
+            // Should be unreachable at this stage
+            ast::ItemKind::MacCall(..) => panic!(
+                "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
+            ),
+
+            // Foreign modules inherit level from parents.
+            ast::ItemKind::ForeignMod(..) => {
+                let parent_id = self.r.local_parent(def_id);
+                self.update(def_id, Visibility::Public, parent_id, Level::Direct);
+            }
+
+            ast::ItemKind::Mod(..) => {
+                self.set_bindings_effective_visibilities(def_id);
+                visit::walk_item(self, item);
+            }
+
+            ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
+                self.set_bindings_effective_visibilities(def_id);
+                for variant in variants {
+                    let variant_def_id = self.r.local_def_id(variant.id);
+                    for field in variant.data.fields() {
+                        let field_def_id = self.r.local_def_id(field.id);
+                        let vis = self.r.visibilities[&field_def_id];
+                        self.update(field_def_id, vis, variant_def_id, Level::Direct);
+                    }
+                }
+            }
+
+            ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
+                for field in def.fields() {
+                    let field_def_id = self.r.local_def_id(field.id);
+                    let vis = self.r.visibilities[&field_def_id];
+                    self.update(field_def_id, vis, def_id, Level::Direct);
+                }
+            }
+
+            ast::ItemKind::Trait(..) => {
+                self.set_bindings_effective_visibilities(def_id);
+            }
+
+            ast::ItemKind::ExternCrate(..)
+            | ast::ItemKind::Use(..)
+            | ast::ItemKind::Static(..)
+            | ast::ItemKind::Const(..)
+            | ast::ItemKind::GlobalAsm(..)
+            | ast::ItemKind::TyAlias(..)
+            | ast::ItemKind::TraitAlias(..)
+            | ast::ItemKind::MacroDef(..)
+            | ast::ItemKind::Fn(..) => return,
+        }
+    }
+}
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index e0542d5479f..0c4b35b8833 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1,11 +1,9 @@
-use rustc_ast::{self as ast, NodeId};
+use rustc_ast as ast;
 use rustc_feature::is_builtin_attr_name;
 use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS};
 use rustc_hir::PrimTy;
 use rustc_middle::bug;
 use rustc_middle::ty;
-use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
-use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
@@ -19,7 +17,7 @@ use crate::late::{
 };
 use crate::macros::{sub_namespace_match, MacroRulesScope};
 use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
-use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
+use crate::{Import, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res};
 use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak};
 
@@ -101,7 +99,7 @@ impl<'a> Resolver<'a> {
         };
         let mut scope = match ns {
             _ if is_absolute_path => Scope::CrateRoot,
-            TypeNS | ValueNS => Scope::Module(module, None),
+            TypeNS | ValueNS => Scope::Module(module),
             MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
         };
         let mut ctxt = ctxt.normalize_to_macros_2_0();
@@ -165,7 +163,7 @@ impl<'a> Resolver<'a> {
                     MacroRulesScope::Invocation(invoc_id) => {
                         Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules)
                     }
-                    MacroRulesScope::Empty => Scope::Module(module, None),
+                    MacroRulesScope::Empty => Scope::Module(module),
                 },
                 Scope::CrateRoot => match ns {
                     TypeNS => {
@@ -174,16 +172,10 @@ impl<'a> Resolver<'a> {
                     }
                     ValueNS | MacroNS => break,
                 },
-                Scope::Module(module, prev_lint_id) => {
+                Scope::Module(module) => {
                     use_prelude = !module.no_implicit_prelude;
-                    let derive_fallback_lint_id = match scope_set {
-                        ScopeSet::Late(.., lint_id) => lint_id,
-                        _ => None,
-                    };
-                    match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) {
-                        Some((parent_module, lint_id)) => {
-                            Scope::Module(parent_module, lint_id.or(prev_lint_id))
-                        }
+                    match self.hygienic_lexical_parent(module, &mut ctxt) {
+                        Some(parent_module) => Scope::Module(parent_module),
                         None => {
                             ctxt.adjust(ExpnId::root());
                             match ns {
@@ -215,45 +207,13 @@ impl<'a> Resolver<'a> {
         &mut self,
         module: Module<'a>,
         ctxt: &mut SyntaxContext,
-        derive_fallback_lint_id: Option<NodeId>,
-    ) -> Option<(Module<'a>, Option<NodeId>)> {
+    ) -> Option<Module<'a>> {
         if !module.expansion.outer_expn_is_descendant_of(*ctxt) {
-            return Some((self.expn_def_scope(ctxt.remove_mark()), None));
+            return Some(self.expn_def_scope(ctxt.remove_mark()));
         }
 
         if let ModuleKind::Block = module.kind {
-            return Some((module.parent.unwrap().nearest_item_scope(), None));
-        }
-
-        // We need to support the next case under a deprecation warning
-        // ```
-        // struct MyStruct;
-        // ---- begin: this comes from a proc macro derive
-        // mod implementation_details {
-        //     // Note that `MyStruct` is not in scope here.
-        //     impl SomeTrait for MyStruct { ... }
-        // }
-        // ---- end
-        // ```
-        // So we have to fall back to the module's parent during lexical resolution in this case.
-        if derive_fallback_lint_id.is_some() {
-            if let Some(parent) = module.parent {
-                // Inner module is inside the macro, parent module is outside of the macro.
-                if module.expansion != parent.expansion
-                    && module.expansion.is_descendant_of(parent.expansion)
-                {
-                    // The macro is a proc macro derive
-                    if let Some(def_id) = module.expansion.expn_data().macro_def_id {
-                        let ext = self.get_macro_by_def_id(def_id).ext;
-                        if ext.builtin_name.is_none()
-                            && ext.macro_kind() == MacroKind::Derive
-                            && parent.expansion.outer_expn_is_descendant_of(*ctxt)
-                        {
-                            return Some((parent, derive_fallback_lint_id));
-                        }
-                    }
-                }
-            }
+            return Some(module.parent.unwrap().nearest_item_scope());
         }
 
         None
@@ -510,7 +470,7 @@ impl<'a> Resolver<'a> {
                             Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
                         }
                     }
-                    Scope::Module(module, derive_fallback_lint_id) => {
+                    Scope::Module(module) => {
                         let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
                         let binding = this.resolve_ident_in_module_unadjusted_ext(
                             ModuleOrUniformRoot::Module(module),
@@ -523,21 +483,6 @@ impl<'a> Resolver<'a> {
                         );
                         match binding {
                             Ok(binding) => {
-                                if let Some(lint_id) = derive_fallback_lint_id {
-                                    this.lint_buffer.buffer_lint_with_diagnostic(
-                                        PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
-                                        lint_id,
-                                        orig_ident.span,
-                                        &format!(
-                                            "cannot find {} `{}` in this scope",
-                                            ns.descr(),
-                                            ident
-                                        ),
-                                        BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(
-                                            orig_ident.span,
-                                        ),
-                                    );
-                                }
                                 let misc_flags = if ptr::eq(module, this.graph_root) {
                                     Flags::MISC_SUGGEST_CRATE
                                 } else if module.is_normal() {
@@ -915,7 +860,11 @@ impl<'a> Resolver<'a> {
             }
 
             if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT {
-                if let NameBindingKind::Res(_, true) = binding.kind {
+                if let NameBindingKind::Import {
+                    import: Import { kind: ImportKind::MacroExport, .. },
+                    ..
+                } = binding.kind
+                {
                     self.macro_expanded_macro_export_errors.insert((path_span, binding.span));
                 }
             }
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 9e2234ae4a5..bdb852548b8 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -2,7 +2,7 @@
 
 use crate::diagnostics::{import_candidates, Suggestion};
 use crate::Determinacy::{self, *};
-use crate::Namespace::{self, *};
+use crate::Namespace::*;
 use crate::{module_to_string, names_to_string, ImportSuggestion};
 use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
 use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
@@ -44,20 +44,36 @@ pub enum ImportKind<'a> {
         type_ns_only: bool,
         /// Did this import result from a nested import? ie. `use foo::{bar, baz};`
         nested: bool,
+        /// The ID of the `UseTree` that imported this `Import`.
+        ///
+        /// In the case where the `Import` was expanded from a "nested" use tree,
+        /// this id is the ID of the leaf tree. For example:
+        ///
+        /// ```ignore (pacify the merciless tidy)
+        /// use foo::bar::{a, b}
+        /// ```
+        ///
+        /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree`
+        /// for `a` in this field.
+        id: NodeId,
         /// Additional `NodeId`s allocated to a `ast::UseTree` for automatically generated `use` statement
         /// (eg. implicit struct constructors)
         additional_ids: (NodeId, NodeId),
     },
     Glob {
         is_prelude: bool,
-        max_vis: Cell<Option<ty::Visibility>>, // The visibility of the greatest re-export.
-                                               // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
+        // The visibility of the greatest re-export.
+        // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
+        max_vis: Cell<Option<ty::Visibility>>,
+        id: NodeId,
     },
     ExternCrate {
         source: Option<Symbol>,
         target: Ident,
+        id: NodeId,
     },
     MacroUse,
+    MacroExport,
 }
 
 /// Manually implement `Debug` for `ImportKind` because the `source/target_bindings`
@@ -71,6 +87,7 @@ impl<'a> std::fmt::Debug for ImportKind<'a> {
                 ref target,
                 ref type_ns_only,
                 ref nested,
+                ref id,
                 ref additional_ids,
                 // Ignore the following to avoid an infinite loop while printing.
                 source_bindings: _,
@@ -81,19 +98,23 @@ impl<'a> std::fmt::Debug for ImportKind<'a> {
                 .field("target", target)
                 .field("type_ns_only", type_ns_only)
                 .field("nested", nested)
+                .field("id", id)
                 .field("additional_ids", additional_ids)
                 .finish_non_exhaustive(),
-            Glob { ref is_prelude, ref max_vis } => f
+            Glob { ref is_prelude, ref max_vis, ref id } => f
                 .debug_struct("Glob")
                 .field("is_prelude", is_prelude)
                 .field("max_vis", max_vis)
+                .field("id", id)
                 .finish(),
-            ExternCrate { ref source, ref target } => f
+            ExternCrate { ref source, ref target, ref id } => f
                 .debug_struct("ExternCrate")
                 .field("source", source)
                 .field("target", target)
+                .field("id", id)
                 .finish(),
             MacroUse => f.debug_struct("MacroUse").finish(),
+            MacroExport => f.debug_struct("MacroExport").finish(),
         }
     }
 }
@@ -103,24 +124,15 @@ impl<'a> std::fmt::Debug for ImportKind<'a> {
 pub(crate) struct Import<'a> {
     pub kind: ImportKind<'a>,
 
-    /// The ID of the `extern crate`, `UseTree` etc that imported this `Import`.
-    ///
-    /// In the case where the `Import` was expanded from a "nested" use tree,
-    /// this id is the ID of the leaf tree. For example:
-    ///
-    /// ```ignore (pacify the merciless tidy)
+    /// Node ID of the "root" use item -- this is always the same as `ImportKind`'s `id`
+    /// (if it exists) except in the case of "nested" use trees, in which case
+    /// it will be the ID of the root use tree. e.g., in the example
+    /// ```ignore (incomplete code)
     /// use foo::bar::{a, b}
     /// ```
-    ///
-    /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree`
-    /// for `a` in this field.
-    pub id: NodeId,
-
-    /// The `id` of the "root" use-kind -- this is always the same as
-    /// `id` except in the case of "nested" use trees, in which case
-    /// it will be the `id` of the root use tree. e.g., in the example
-    /// from `id`, this would be the ID of the `use foo::bar`
-    /// `UseTree` node.
+    /// this would be the ID of the `use foo::bar` `UseTree` node.
+    /// In case of imports without their own node ID it's the closest node that can be used,
+    /// for example, for reporting lints.
     pub root_id: NodeId,
 
     /// Span of the entire use statement.
@@ -161,6 +173,15 @@ impl<'a> Import<'a> {
     pub(crate) fn expect_vis(&self) -> ty::Visibility {
         self.vis.get().expect("encountered cleared import visibility")
     }
+
+    pub(crate) fn id(&self) -> Option<NodeId> {
+        match self.kind {
+            ImportKind::Single { id, .. }
+            | ImportKind::Glob { id, .. }
+            | ImportKind::ExternCrate { id, .. } => Some(id),
+            ImportKind::MacroUse | ImportKind::MacroExport => None,
+        }
+    }
 }
 
 /// Records information about the resolution of a name in a namespace of a module.
@@ -252,7 +273,7 @@ impl<'a> Resolver<'a> {
         self.set_binding_parent_module(binding, module);
         self.update_resolution(module, key, |this, resolution| {
             if let Some(old_binding) = resolution.binding {
-                if res == Res::Err {
+                if res == Res::Err && old_binding.res() != Res::Err {
                     // Do not override real bindings with `Res::Err`s from error recovery.
                     return Ok(());
                 }
@@ -368,33 +389,10 @@ impl<'a> Resolver<'a> {
             self.record_use(target, dummy_binding, false);
         } else if import.imported_module.get().is_none() {
             import.used.set(true);
-            self.used_imports.insert(import.id);
-        }
-    }
-
-    /// Take primary and additional node IDs from an import and select one that corresponds to the
-    /// given namespace. The logic must match the corresponding logic from `fn lower_use_tree` that
-    /// assigns resolutons to IDs.
-    pub(crate) fn import_id_for_ns(&self, import: &Import<'_>, ns: Namespace) -> NodeId {
-        if let ImportKind::Single { additional_ids: (id1, id2), .. } = import.kind {
-            if let Some(resolutions) = self.import_res_map.get(&import.id) {
-                assert!(resolutions[ns].is_some(), "incorrectly finalized import");
-                return match ns {
-                    TypeNS => import.id,
-                    ValueNS => match resolutions.type_ns {
-                        Some(_) => id1,
-                        None => import.id,
-                    },
-                    MacroNS => match (resolutions.type_ns, resolutions.value_ns) {
-                        (Some(_), Some(_)) => id2,
-                        (Some(_), None) | (None, Some(_)) => id1,
-                        (None, None) => import.id,
-                    },
-                };
+            if let Some(id) = import.id() {
+                self.used_imports.insert(id);
             }
         }
-
-        import.id
     }
 }
 
@@ -743,47 +741,51 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             PathResult::Indeterminate => unreachable!(),
         };
 
-        let (ident, target, source_bindings, target_bindings, type_ns_only) = match import.kind {
-            ImportKind::Single {
-                source,
-                target,
-                ref source_bindings,
-                ref target_bindings,
-                type_ns_only,
-                ..
-            } => (source, target, source_bindings, target_bindings, type_ns_only),
-            ImportKind::Glob { is_prelude, ref max_vis } => {
-                if import.module_path.len() <= 1 {
-                    // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
-                    // 2 segments, so the `resolve_path` above won't trigger it.
-                    let mut full_path = import.module_path.clone();
-                    full_path.push(Segment::from_ident(Ident::empty()));
-                    self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
-                }
+        let (ident, target, source_bindings, target_bindings, type_ns_only, import_id) =
+            match import.kind {
+                ImportKind::Single {
+                    source,
+                    target,
+                    ref source_bindings,
+                    ref target_bindings,
+                    type_ns_only,
+                    id,
+                    ..
+                } => (source, target, source_bindings, target_bindings, type_ns_only, id),
+                ImportKind::Glob { is_prelude, ref max_vis, id } => {
+                    if import.module_path.len() <= 1 {
+                        // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
+                        // 2 segments, so the `resolve_path` above won't trigger it.
+                        let mut full_path = import.module_path.clone();
+                        full_path.push(Segment::from_ident(Ident::empty()));
+                        self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
+                    }
 
-                if let ModuleOrUniformRoot::Module(module) = module {
-                    if ptr::eq(module, import.parent_scope.module) {
-                        // Importing a module into itself is not allowed.
-                        return Some(UnresolvedImportError {
-                            span: import.span,
-                            label: Some(String::from("cannot glob-import a module into itself")),
-                            note: None,
-                            suggestion: None,
-                            candidate: None,
-                        });
+                    if let ModuleOrUniformRoot::Module(module) = module {
+                        if ptr::eq(module, import.parent_scope.module) {
+                            // Importing a module into itself is not allowed.
+                            return Some(UnresolvedImportError {
+                                span: import.span,
+                                label: Some(String::from(
+                                    "cannot glob-import a module into itself",
+                                )),
+                                note: None,
+                                suggestion: None,
+                                candidate: None,
+                            });
+                        }
                     }
-                }
-                if !is_prelude
+                    if !is_prelude
                     && let Some(max_vis) = max_vis.get()
                     && !max_vis.is_at_least(import.expect_vis(), &*self.r)
                 {
                     let msg = "glob import doesn't reexport anything because no candidate is public enough";
-                    self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg);
+                    self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg);
                 }
-                return None;
-            }
-            _ => unreachable!(),
-        };
+                    return None;
+                }
+                _ => unreachable!(),
+            };
 
         let mut all_ns_err = true;
         self.r.per_ns(|this, ns| {
@@ -883,7 +885,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                                         match binding.kind {
                                             // Never suggest the name that has binding error
                                             // i.e., the name that cannot be previously resolved
-                                            NameBindingKind::Res(Res::Err, _) => None,
+                                            NameBindingKind::Res(Res::Err) => None,
                                             _ => Some(i.name),
                                         }
                                     }
@@ -985,7 +987,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 );
                 self.r.lint_buffer.buffer_lint(
                     PUB_USE_OF_PRIVATE_EXTERN_CRATE,
-                    import.id,
+                    import_id,
                     import.span,
                     &msg,
                 );
@@ -1014,7 +1016,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     let mut err =
                         struct_span_err!(self.r.session, import.span, E0364, "{error_msg}");
                     match binding.kind {
-                        NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id), _)
+                        NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id))
                             // exclude decl_macro
                             if self.r.get_macro_by_def_id(def_id).macro_rules =>
                         {
@@ -1054,7 +1056,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         // purposes it's good enough to just favor one over the other.
         self.r.per_ns(|this, ns| {
             if let Ok(binding) = source_bindings[ns].get() {
-                this.import_res_map.entry(import.id).or_default()[ns] = Some(binding.res());
+                this.import_res_map.entry(import_id).or_default()[ns] = Some(binding.res());
             }
         });
 
@@ -1072,6 +1074,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         target_bindings: &PerNS<Cell<Option<&'b NameBinding<'b>>>>,
         target: Ident,
     ) {
+        // This function is only called for single imports.
+        let ImportKind::Single { id, .. } = import.kind else { unreachable!() };
+
         // Skip if the import was produced by a macro.
         if import.parent_scope.expansion != LocalExpnId::ROOT {
             return;
@@ -1119,7 +1124,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             redundant_spans.dedup();
             self.r.lint_buffer.buffer_lint_with_diagnostic(
                 UNUSED_IMPORTS,
-                import.id,
+                id,
                 import.span,
                 &format!("the item `{}` is imported redundantly", ident),
                 BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident),
@@ -1128,6 +1133,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
     }
 
     fn resolve_glob_import(&mut self, import: &'b Import<'b>) {
+        // This function is only called for glob imports.
+        let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() };
+
         let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else {
             self.r.session.span_err(import.span, "cannot glob-import all possible crates");
             return;
@@ -1138,7 +1146,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             return;
         } else if ptr::eq(module, import.parent_scope.module) {
             return;
-        } else if let ImportKind::Glob { is_prelude: true, .. } = import.kind {
+        } else if is_prelude {
             self.r.prelude = Some(module);
             return;
         }
@@ -1170,7 +1178,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         }
 
         // Record the destination of this import
-        self.r.record_partial_res(import.id, PartialRes::new(module.res().unwrap()));
+        self.r.record_partial_res(id, PartialRes::new(module.res().unwrap()));
     }
 
     // Miscellaneous post-processing, including recording re-exports,
@@ -1229,5 +1237,6 @@ fn import_kind_to_string(import_kind: &ImportKind<'_>) -> String {
         ImportKind::Glob { .. } => "*".to_string(),
         ImportKind::ExternCrate { .. } => "<extern crate>".to_string(),
         ImportKind::MacroUse => "#[macro_use]".to_string(),
+        ImportKind::MacroExport => "#[macro_export]".to_string(),
     }
 }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index cc877e2fd30..6d2ee25df32 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -30,8 +30,9 @@ use rustc_span::{BytePos, Span};
 use smallvec::{smallvec, SmallVec};
 
 use rustc_span::source_map::{respan, Spanned};
+use std::assert_matches::debug_assert_matches;
 use std::collections::{hash_map::Entry, BTreeSet};
-use std::mem::{replace, take};
+use std::mem::{replace, swap, take};
 
 mod diagnostics;
 
@@ -224,22 +225,14 @@ enum LifetimeUseSet {
 
 #[derive(Copy, Clone, Debug)]
 enum LifetimeRibKind {
-    /// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
-    Item,
-
+    // -- Ribs introducing named lifetimes
+    //
     /// This rib declares generic parameters.
+    /// Only for this kind the `LifetimeRib::bindings` field can be non-empty.
     Generics { binder: NodeId, span: Span, kind: LifetimeBinderKind },
 
-    /// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
-    /// generics. We are disallowing this until we can decide on how we want to handle non-'static
-    /// lifetimes in const generics. See issue #74052 for discussion.
-    ConstGeneric,
-
-    /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
-    /// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by
-    /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
-    AnonConst,
-
+    // -- Ribs introducing unnamed lifetimes
+    //
     /// Create a new anonymous lifetime parameter and reference it.
     ///
     /// If `report_in_path`, report an error when encountering lifetime elision in a path:
@@ -256,16 +249,31 @@ enum LifetimeRibKind {
     /// ```
     AnonymousCreateParameter { binder: NodeId, report_in_path: bool },
 
+    /// Replace all anonymous lifetimes by provided lifetime.
+    Elided(LifetimeRes),
+
+    // -- Barrier ribs that stop lifetime lookup, or continue it but produce an error later.
+    //
     /// Give a hard error when either `&` or `'_` is written. Used to
     /// rule out things like `where T: Foo<'_>`. Does not imply an
     /// error on default object bounds (e.g., `Box<dyn Foo>`).
     AnonymousReportError,
 
-    /// Replace all anonymous lifetimes by provided lifetime.
-    Elided(LifetimeRes),
-
     /// Signal we cannot find which should be the anonymous lifetime.
     ElisionFailure,
+
+    /// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
+    /// generics. We are disallowing this until we can decide on how we want to handle non-'static
+    /// lifetimes in const generics. See issue #74052 for discussion.
+    ConstGeneric,
+
+    /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
+    /// This function will emit an error if `generic_const_exprs` is not enabled, the body
+    /// identified by `body_id` is an anonymous constant and `lifetime_ref` is non-static.
+    AnonConst,
+
+    /// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
+    Item,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -517,6 +525,9 @@ struct DiagnosticMetadata<'ast> {
     /// Used to detect possible `if let` written without `let` and to provide structured suggestion.
     in_if_condition: Option<&'ast Expr>,
 
+    /// Used to detect possible new binding written without `let` and to provide structured suggestion.
+    in_assignment: Option<&'ast Expr>,
+
     /// If we are currently in a trait object definition. Used to point at the bounds when
     /// encountering a struct or enum.
     current_trait_object: Option<&'ast [ast::GenericBound]>,
@@ -558,7 +569,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
     /// They will be used to determine the correct lifetime for the fn return type.
     /// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named
     /// lifetimes.
-    lifetime_elision_candidates: Option<FxIndexMap<LifetimeRes, LifetimeElisionCandidate>>,
+    lifetime_elision_candidates: Option<Vec<(LifetimeRes, LifetimeElisionCandidate)>>,
 
     /// The trait that the current context can refer to.
     current_trait_ref: Option<(Module<'a>, TraitRef)>,
@@ -748,35 +759,31 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
     fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
         match foreign_item.kind {
             ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
-                self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
-                    this.with_generic_param_rib(
-                        &generics.params,
-                        ItemRibKind(HasGenericParams::Yes(generics.span)),
-                        LifetimeRibKind::Generics {
-                            binder: foreign_item.id,
-                            kind: LifetimeBinderKind::Item,
-                            span: generics.span,
-                        },
-                        |this| visit::walk_foreign_item(this, foreign_item),
-                    )
-                });
+                self.with_generic_param_rib(
+                    &generics.params,
+                    ItemRibKind(HasGenericParams::Yes(generics.span)),
+                    LifetimeRibKind::Generics {
+                        binder: foreign_item.id,
+                        kind: LifetimeBinderKind::Item,
+                        span: generics.span,
+                    },
+                    |this| visit::walk_foreign_item(this, foreign_item),
+                );
             }
             ForeignItemKind::Fn(box Fn { ref generics, .. }) => {
-                self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
-                    this.with_generic_param_rib(
-                        &generics.params,
-                        ItemRibKind(HasGenericParams::Yes(generics.span)),
-                        LifetimeRibKind::Generics {
-                            binder: foreign_item.id,
-                            kind: LifetimeBinderKind::Function,
-                            span: generics.span,
-                        },
-                        |this| visit::walk_foreign_item(this, foreign_item),
-                    )
-                });
+                self.with_generic_param_rib(
+                    &generics.params,
+                    ItemRibKind(HasGenericParams::Yes(generics.span)),
+                    LifetimeRibKind::Generics {
+                        binder: foreign_item.id,
+                        kind: LifetimeBinderKind::Function,
+                        span: generics.span,
+                    },
+                    |this| visit::walk_foreign_item(this, foreign_item),
+                );
             }
             ForeignItemKind::Static(..) => {
-                self.with_item_rib(|this| {
+                self.with_static_rib(|this| {
                     visit::walk_foreign_item(this, foreign_item);
                 });
             }
@@ -1391,9 +1398,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             return self.resolve_anonymous_lifetime(lifetime, false);
         }
 
-        let mut indices = (0..self.lifetime_ribs.len()).rev();
-        for i in &mut indices {
-            let rib = &self.lifetime_ribs[i];
+        let mut lifetime_rib_iter = self.lifetime_ribs.iter().rev();
+        while let Some(rib) = lifetime_rib_iter.next() {
             let normalized_ident = ident.normalize_to_macros_2_0();
             if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
                 self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named);
@@ -1423,9 +1429,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                     } else {
                                         LifetimeUseSet::Many
                                     }),
-                                    LifetimeRibKind::Generics { .. }
-                                    | LifetimeRibKind::ConstGeneric
-                                    | LifetimeRibKind::AnonConst => None,
+                                    LifetimeRibKind::Generics { .. } => None,
+                                    LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => {
+                                        span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind)
+                                    }
                                 })
                                 .unwrap_or(LifetimeUseSet::Many);
                             debug!(?use_ctxt, ?use_set);
@@ -1460,13 +1467,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     );
                     return;
                 }
-                _ => {}
+                LifetimeRibKind::AnonymousCreateParameter { .. }
+                | LifetimeRibKind::Elided(_)
+                | LifetimeRibKind::Generics { .. }
+                | LifetimeRibKind::ElisionFailure
+                | LifetimeRibKind::AnonymousReportError => {}
             }
         }
 
         let mut outer_res = None;
-        for i in indices {
-            let rib = &self.lifetime_ribs[i];
+        for rib in lifetime_rib_iter {
             let normalized_ident = ident.normalize_to_macros_2_0();
             if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) {
                 outer_res = Some(outer);
@@ -1493,8 +1503,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             count: 1,
         };
         let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
-        for i in (0..self.lifetime_ribs.len()).rev() {
-            let rib = &mut self.lifetime_ribs[i];
+        for rib in self.lifetime_ribs.iter().rev() {
             debug!(?rib.kind);
             match rib.kind {
                 LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
@@ -1534,9 +1543,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     return;
                 }
                 LifetimeRibKind::Item => break,
-                LifetimeRibKind::Generics { .. }
-                | LifetimeRibKind::ConstGeneric
-                | LifetimeRibKind::AnonConst => {}
+                LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {}
+                LifetimeRibKind::AnonConst => {
+                    // There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`.
+                    span_bug!(lifetime.ident.span, "unexpected rib kind: {:?}", rib.kind)
+                }
             }
         }
         self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
@@ -1751,9 +1762,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
                         break;
                     }
-                    LifetimeRibKind::Generics { .. }
-                    | LifetimeRibKind::ConstGeneric
-                    | LifetimeRibKind::AnonConst => {}
+                    LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {}
+                    LifetimeRibKind::AnonConst => {
+                        // There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`.
+                        span_bug!(elided_lifetime_span, "unexpected rib kind: {:?}", rib.kind)
+                    }
                 }
             }
 
@@ -1790,7 +1803,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         match res {
             LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => {
                 if let Some(ref mut candidates) = self.lifetime_elision_candidates {
-                    candidates.insert(res, candidate);
+                    candidates.push((res, candidate));
                 }
             }
             LifetimeRes::Infer | LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {}
@@ -1843,25 +1856,45 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         has_self: bool,
         inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)>,
     ) -> Result<LifetimeRes, (Vec<MissingLifetime>, Vec<ElisionFnParameter>)> {
-        let outer_candidates =
-            replace(&mut self.lifetime_elision_candidates, Some(Default::default()));
+        enum Elision {
+            /// We have not found any candidate.
+            None,
+            /// We have a candidate bound to `self`.
+            Self_(LifetimeRes),
+            /// We have a candidate bound to a parameter.
+            Param(LifetimeRes),
+            /// We failed elision.
+            Err,
+        }
+
+        // Save elision state to reinstate it later.
+        let outer_candidates = self.lifetime_elision_candidates.take();
 
-        let mut elision_lifetime = None;
-        let mut lifetime_count = 0;
+        // Result of elision.
+        let mut elision_lifetime = Elision::None;
+        // Information for diagnostics.
         let mut parameter_info = Vec::new();
+        let mut all_candidates = Vec::new();
 
         let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
         for (index, (pat, ty)) in inputs.enumerate() {
             debug!(?pat, ?ty);
-            if let Some(pat) = pat {
-                self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
-            }
+            self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
+                if let Some(pat) = pat {
+                    this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
+                }
+            });
+
+            // Record elision candidates only for this parameter.
+            debug_assert_matches!(self.lifetime_elision_candidates, None);
+            self.lifetime_elision_candidates = Some(Default::default());
             self.visit_ty(ty);
+            let local_candidates = self.lifetime_elision_candidates.take();
 
-            if let Some(ref candidates) = self.lifetime_elision_candidates {
-                let new_count = candidates.len();
-                let local_count = new_count - lifetime_count;
-                if local_count != 0 {
+            if let Some(candidates) = local_candidates {
+                let distinct: FxHashSet<_> = candidates.iter().map(|(res, _)| *res).collect();
+                let lifetime_count = distinct.len();
+                if lifetime_count != 0 {
                     parameter_info.push(ElisionFnParameter {
                         index,
                         ident: if let Some(pat) = pat && let PatKind::Ident(_, ident, _) = pat.kind {
@@ -1869,48 +1902,64 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         } else {
                             None
                         },
-                        lifetime_count: local_count,
+                        lifetime_count,
                         span: ty.span,
                     });
+                    all_candidates.extend(candidates.into_iter().filter_map(|(_, candidate)| {
+                        match candidate {
+                            LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => {
+                                None
+                            }
+                            LifetimeElisionCandidate::Missing(missing) => Some(missing),
+                        }
+                    }));
+                }
+                let mut distinct_iter = distinct.into_iter();
+                if let Some(res) = distinct_iter.next() {
+                    match elision_lifetime {
+                        // We are the first parameter to bind lifetimes.
+                        Elision::None => {
+                            if distinct_iter.next().is_none() {
+                                // We have a single lifetime => success.
+                                elision_lifetime = Elision::Param(res)
+                            } else {
+                                // We have have multiple lifetimes => error.
+                                elision_lifetime = Elision::Err;
+                            }
+                        }
+                        // We have 2 parameters that bind lifetimes => error.
+                        Elision::Param(_) => elision_lifetime = Elision::Err,
+                        // `self` elision takes precedence over everything else.
+                        Elision::Self_(_) | Elision::Err => {}
+                    }
                 }
-                lifetime_count = new_count;
             }
 
             // Handle `self` specially.
             if index == 0 && has_self {
                 let self_lifetime = self.find_lifetime_for_self(ty);
                 if let Set1::One(lifetime) = self_lifetime {
-                    elision_lifetime = Some(lifetime);
-                    self.lifetime_elision_candidates = None;
+                    // We found `self` elision.
+                    elision_lifetime = Elision::Self_(lifetime);
                 } else {
-                    self.lifetime_elision_candidates = Some(Default::default());
-                    lifetime_count = 0;
+                    // We do not have `self` elision: disregard the `Elision::Param` that we may
+                    // have found.
+                    elision_lifetime = Elision::None;
                 }
             }
             debug!("(resolving function / closure) recorded parameter");
         }
 
-        let all_candidates = replace(&mut self.lifetime_elision_candidates, outer_candidates);
-        debug!(?all_candidates);
+        // Reinstate elision state.
+        debug_assert_matches!(self.lifetime_elision_candidates, None);
+        self.lifetime_elision_candidates = outer_candidates;
 
-        if let Some(res) = elision_lifetime {
+        if let Elision::Param(res) | Elision::Self_(res) = elision_lifetime {
             return Ok(res);
         }
 
-        // We do not have a `self` candidate, look at the full list.
-        let all_candidates = all_candidates.unwrap();
-        if all_candidates.len() == 1 {
-            Ok(*all_candidates.first().unwrap().0)
-        } else {
-            let all_candidates = all_candidates
-                .into_iter()
-                .filter_map(|(_, candidate)| match candidate {
-                    LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => None,
-                    LifetimeElisionCandidate::Missing(missing) => Some(missing),
-                })
-                .collect();
-            Err((all_candidates, parameter_info))
-        }
+        // We do not have a candidate.
+        Err((all_candidates, parameter_info))
     }
 
     /// List all the lifetimes that appear in the provided type.
@@ -1928,11 +1977,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 match ty.kind {
                     TyKind::ImplicitSelf => true,
                     TyKind::Path(None, _) => {
-                        let path_res = self.r.partial_res_map[&ty.id].expect_full_res();
-                        if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path_res {
+                        let path_res = self.r.partial_res_map[&ty.id].full_res();
+                        if let Some(Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }) = path_res {
                             return true;
                         }
-                        Some(path_res) == self.impl_self
+                        self.impl_self.is_some() && path_res == self.impl_self
                     }
                     _ => false,
                 }
@@ -2204,7 +2253,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             }
 
             ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
-                self.with_item_rib(|this| {
+                self.with_static_rib(|this| {
                     this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
                         this.visit_ty(ty);
                     });
@@ -2380,7 +2429,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         // Do not account for the parameters we just bound for function lifetime elision.
         if let Some(ref mut candidates) = self.lifetime_elision_candidates {
             for (_, res) in function_lifetime_rib.bindings.values() {
-                candidates.remove(res);
+                candidates.retain(|(r, _)| r != res);
             }
         }
 
@@ -2399,11 +2448,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         self.label_ribs.pop();
     }
 
-    fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) {
+    fn with_static_rib(&mut self, f: impl FnOnce(&mut Self)) {
         let kind = ItemRibKind(HasGenericParams::No);
-        self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
-            this.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
-        })
+        self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
     }
 
     // HACK(min_const_generics,const_evaluatable_unchecked): We
@@ -2827,10 +2874,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
     fn resolve_params(&mut self, params: &'ast [Param]) {
         let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
-        for Param { pat, ty, .. } in params {
-            self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
+        self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
+            for Param { pat, .. } in params {
+                this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
+            }
+        });
+        for Param { ty, .. } in params {
             self.visit_ty(ty);
-            debug!("(resolving function / closure) recorded parameter");
         }
     }
 
@@ -3319,11 +3369,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             let (mut err, candidates) =
                 this.smart_resolve_report_errors(path, path_span, PathSource::Type, None);
 
-            if candidates.is_empty() {
-                err.cancel();
-                return Some(parent_err);
-            }
-
             // There are two different error messages user might receive at
             // this point:
             // - E0412 cannot find type `{}` in this scope
@@ -3333,37 +3378,62 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             // latter one - for paths in expression-position.
             //
             // Thus (since we're in expression-position at this point), not to
-            // confuse the user, we want to keep the *message* from E0432 (so
+            // confuse the user, we want to keep the *message* from E0433 (so
             // `parent_err`), but we want *hints* from E0412 (so `err`).
             //
             // And that's what happens below - we're just mixing both messages
             // into a single one.
             let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node);
 
+            // overwrite all properties with the parent's error message
             err.message = take(&mut parent_err.message);
             err.code = take(&mut parent_err.code);
+            swap(&mut err.span, &mut parent_err.span);
             err.children = take(&mut parent_err.children);
+            err.sort_span = parent_err.sort_span;
+            err.is_lint = parent_err.is_lint;
+
+            // merge the parent's suggestions with the typo suggestions
+            fn append_result<T, E>(res1: &mut Result<Vec<T>, E>, res2: Result<Vec<T>, E>) {
+                match res1 {
+                    Ok(vec1) => match res2 {
+                        Ok(mut vec2) => vec1.append(&mut vec2),
+                        Err(e) => *res1 = Err(e),
+                    },
+                    Err(_) => (),
+                };
+            }
+            append_result(&mut err.suggestions, parent_err.suggestions.clone());
 
             parent_err.cancel();
 
             let def_id = this.parent_scope.module.nearest_parent_mod();
 
             if this.should_report_errs() {
-                this.r.use_injections.push(UseError {
-                    err,
-                    candidates,
-                    def_id,
-                    instead: false,
-                    suggestion: None,
-                    path: path.into(),
-                    is_call: source.is_call(),
-                });
+                if candidates.is_empty() {
+                    // When there is no suggested imports, we can just emit the error
+                    // and suggestions immediately. Note that we bypass the usually error
+                    // reporting routine (ie via `self.r.report_error`) because we need
+                    // to post-process the `ResolutionError` above.
+                    err.emit();
+                } else {
+                    // If there are suggested imports, the error reporting is delayed
+                    this.r.use_injections.push(UseError {
+                        err,
+                        candidates,
+                        def_id,
+                        instead: false,
+                        suggestion: None,
+                        path: path.into(),
+                        is_call: source.is_call(),
+                    });
+                }
             } else {
                 err.cancel();
             }
 
             // We don't return `Some(parent_err)` here, because the error will
-            // be already printed as part of the `use` injections
+            // be already printed either immediately or as part of the `use` injections
             None
         };
 
@@ -3893,6 +3963,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 self.resolve_expr(elem, Some(expr));
                 self.visit_expr(idx);
             }
+            ExprKind::Assign(..) => {
+                let old = self.diagnostic_metadata.in_assignment.replace(expr);
+                visit::walk_expr(self, expr);
+                self.diagnostic_metadata.in_assignment = old;
+            }
             _ => {
                 visit::walk_expr(self, expr);
             }
@@ -3938,7 +4013,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         fn_id: NodeId,
         async_node_id: Option<(NodeId, Span)>,
     ) {
-        if let Some((async_node_id, _)) = async_node_id {
+        if let Some((async_node_id, span)) = async_node_id {
             let mut extra_lifetime_params =
                 self.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default();
             for rib in self.lifetime_ribs.iter().rev() {
@@ -3952,7 +4027,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                             extra_lifetime_params.extend(earlier_fresh);
                         }
                     }
-                    _ => {}
+                    LifetimeRibKind::Generics { .. } => {}
+                    _ => {
+                        // We are in a function definition. We should only find `Generics`
+                        // and `AnonymousCreateParameter` inside the innermost `Item`.
+                        span_bug!(span, "unexpected rib kind: {:?}", rib.kind)
+                    }
                 }
             }
             self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 13cd7987e92..103187b00d1 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -38,8 +38,8 @@ type Res = def::Res<ast::NodeId>;
 /// A field or associated item from self type suggested in case of resolution failure.
 enum AssocSuggestion {
     Field,
-    MethodWithSelf,
-    AssocFn,
+    MethodWithSelf { called: bool },
+    AssocFn { called: bool },
     AssocType,
     AssocConst,
 }
@@ -48,8 +48,14 @@ impl AssocSuggestion {
     fn action(&self) -> &'static str {
         match self {
             AssocSuggestion::Field => "use the available field",
-            AssocSuggestion::MethodWithSelf => "call the method with the fully-qualified path",
-            AssocSuggestion::AssocFn => "call the associated function",
+            AssocSuggestion::MethodWithSelf { called: true } => {
+                "call the method with the fully-qualified path"
+            }
+            AssocSuggestion::MethodWithSelf { called: false } => {
+                "refer to the method with the fully-qualified path"
+            }
+            AssocSuggestion::AssocFn { called: true } => "call the associated function",
+            AssocSuggestion::AssocFn { called: false } => "refer to the associated function",
             AssocSuggestion::AssocConst => "use the associated `const`",
             AssocSuggestion::AssocType => "use the associated type",
         }
@@ -131,6 +137,7 @@ pub(super) enum LifetimeElisionCandidate {
 }
 
 /// Only used for diagnostics.
+#[derive(Debug)]
 struct BaseError {
     msg: String,
     fallback_label: String,
@@ -140,6 +147,22 @@ struct BaseError {
     suggestion: Option<(Span, &'static str, String)>,
 }
 
+#[derive(Debug)]
+enum TypoCandidate {
+    Typo(TypoSuggestion),
+    Shadowed(Res, Option<Span>),
+    None,
+}
+
+impl TypoCandidate {
+    fn to_opt_suggestion(self) -> Option<TypoSuggestion> {
+        match self {
+            TypoCandidate::Typo(sugg) => Some(sugg),
+            TypoCandidate::Shadowed(_, _) | TypoCandidate::None => None,
+        }
+    }
+}
+
 impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
     fn def_span(&self, def_id: DefId) -> Option<Span> {
         match def_id.krate {
@@ -496,9 +519,12 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         }
 
         // Try Levenshtein algorithm.
-        let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
+        let typo_sugg =
+            self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion();
         if path.len() == 1 && self.self_type_is_available() {
-            if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
+            if let Some(candidate) =
+                self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
+            {
                 let self_is_available = self.self_value_is_available(path[0].ident.span);
                 match candidate {
                     AssocSuggestion::Field => {
@@ -513,16 +539,21 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                             err.span_label(span, "a field by this name exists in `Self`");
                         }
                     }
-                    AssocSuggestion::MethodWithSelf if self_is_available => {
+                    AssocSuggestion::MethodWithSelf { called } if self_is_available => {
+                        let msg = if called {
+                            "you might have meant to call the method"
+                        } else {
+                            "you might have meant to refer to the method"
+                        };
                         err.span_suggestion(
                             span,
-                            "you might have meant to call the method",
+                            msg,
                             format!("self.{path_str}"),
                             Applicability::MachineApplicable,
                         );
                     }
-                    AssocSuggestion::MethodWithSelf
-                    | AssocSuggestion::AssocFn
+                    AssocSuggestion::MethodWithSelf { .. }
+                    | AssocSuggestion::AssocFn { .. }
                     | AssocSuggestion::AssocConst
                     | AssocSuggestion::AssocType => {
                         err.span_suggestion(
@@ -660,7 +691,29 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         let is_expected = &|res| source.is_expected(res);
         let ident_span = path.last().map_or(span, |ident| ident.ident.span);
         let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
+        let is_in_same_file = &|sp1, sp2| {
+            let source_map = self.r.session.source_map();
+            let file1 = source_map.span_to_filename(sp1);
+            let file2 = source_map.span_to_filename(sp2);
+            file1 == file2
+        };
+        // print 'you might have meant' if the candidate is (1) is a shadowed name with
+        // accessible definition and (2) either defined in the same crate as the typo
+        // (could be in a different file) or introduced in the same file as the typo
+        // (could belong to a different crate)
+        if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg
+            && res
+                .opt_def_id()
+                .map_or(false, |id| id.is_local() || is_in_same_file(span, sugg_span))
+        {
+            err.span_label(
+                sugg_span,
+                format!("you might have meant to refer to this {}", res.descr()),
+            );
+            return true;
+        }
         let mut fallback = false;
+        let typo_sugg = typo_sugg.to_opt_suggestion();
         if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {
             fallback = true;
             match self.diagnostic_metadata.current_let_binding {
@@ -679,7 +732,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
 
             // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
             let suggestion = self.get_single_associated_item(&path, &source, is_expected);
-            self.r.add_typo_suggestion(err, suggestion, ident_span);
+            if !self.r.add_typo_suggestion(err, suggestion, ident_span) {
+                fallback = !self.let_binding_suggestion(err, ident_span);
+            }
         }
         fallback
     }
@@ -740,10 +795,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             return false;
         }
         err.code(rustc_errors::error_code!(E0411));
-        err.span_label(
-            span,
-            "`Self` is only available in impls, traits, and type definitions".to_string(),
-        );
+        err.span_label(span, "`Self` is only available in impls, traits, and type definitions");
         if let Some(item_kind) = self.diagnostic_metadata.current_item {
             err.span_label(
                 item_kind.ident.span,
@@ -929,10 +981,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                         .collect();
                 if targets.len() == 1 {
                     let target = targets[0];
-                    return Some(TypoSuggestion::single_item_from_res(
-                        target.0.ident.name,
-                        target.1,
-                    ));
+                    return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1));
                 }
             }
         }
@@ -1076,41 +1125,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         // where a brace being opened means a block is being started. Look
         // ahead for the next text to see if `span` is followed by a `{`.
         let sm = self.r.session.source_map();
-        let mut sp = span;
-        loop {
-            sp = sm.next_point(sp);
-            match sm.span_to_snippet(sp) {
-                Ok(ref snippet) => {
-                    if snippet.chars().any(|c| !c.is_whitespace()) {
-                        break;
-                    }
-                }
-                _ => break,
-            }
-        }
+        let sp = sm.span_look_ahead(span, None, Some(50));
         let followed_by_brace = matches!(sm.span_to_snippet(sp), Ok(ref snippet) if snippet == "{");
         // In case this could be a struct literal that needs to be surrounded
         // by parentheses, find the appropriate span.
-        let mut i = 0;
-        let mut closing_brace = None;
-        loop {
-            sp = sm.next_point(sp);
-            match sm.span_to_snippet(sp) {
-                Ok(ref snippet) => {
-                    if snippet == "}" {
-                        closing_brace = Some(span.to(sp));
-                        break;
-                    }
-                }
-                _ => break,
-            }
-            i += 1;
-            // The bigger the span, the more likely we're incorrect --
-            // bound it to 100 chars long.
-            if i > 100 {
-                break;
-            }
-        }
+        let closing_span = sm.span_look_ahead(span, Some("}"), Some(50));
+        let closing_brace: Option<Span> = sm
+            .span_to_snippet(closing_span)
+            .map_or(None, |s| if s == "}" { Some(span.to(closing_span)) } else { None });
         (followed_by_brace, closing_brace)
     }
 
@@ -1494,6 +1516,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         ident: Ident,
         ns: Namespace,
         filter_fn: FilterFn,
+        called: bool,
     ) -> Option<AssocSuggestion>
     where
         FilterFn: Fn(Res) -> bool,
@@ -1535,9 +1558,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                     return Some(match &assoc_item.kind {
                         ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
                         ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) if sig.decl.has_self() => {
-                            AssocSuggestion::MethodWithSelf
+                            AssocSuggestion::MethodWithSelf { called }
                         }
-                        ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn,
+                        ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called },
                         ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType,
                         ast::AssocItemKind::MacCall(_) => continue,
                     });
@@ -1556,10 +1579,12 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                 let res = binding.res();
                 if filter_fn(res) {
                     if self.r.has_self.contains(&res.def_id()) {
-                        return Some(AssocSuggestion::MethodWithSelf);
+                        return Some(AssocSuggestion::MethodWithSelf { called });
                     } else {
                         match res {
-                            Res::Def(DefKind::AssocFn, _) => return Some(AssocSuggestion::AssocFn),
+                            Res::Def(DefKind::AssocFn, _) => {
+                                return Some(AssocSuggestion::AssocFn { called });
+                            }
                             Res::Def(DefKind::AssocConst, _) => {
                                 return Some(AssocSuggestion::AssocConst);
                             }
@@ -1581,22 +1606,38 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         path: &[Segment],
         ns: Namespace,
         filter_fn: &impl Fn(Res) -> bool,
-    ) -> Option<TypoSuggestion> {
+    ) -> TypoCandidate {
         let mut names = Vec::new();
         if path.len() == 1 {
+            let mut ctxt = path.last().unwrap().ident.span.ctxt();
+
             // Search in lexical scope.
             // Walk backwards up the ribs in scope and collect candidates.
             for rib in self.ribs[ns].iter().rev() {
+                let rib_ctxt = if rib.kind.contains_params() {
+                    ctxt.normalize_to_macros_2_0()
+                } else {
+                    ctxt.normalize_to_macro_rules()
+                };
+
                 // Locals and type parameters
                 for (ident, &res) in &rib.bindings {
-                    if filter_fn(res) {
-                        names.push(TypoSuggestion::typo_from_res(ident.name, res));
+                    if filter_fn(res) && ident.span.ctxt() == rib_ctxt {
+                        names.push(TypoSuggestion::typo_from_ident(*ident, res));
                     }
                 }
+
+                if let RibKind::MacroDefinition(def) = rib.kind && def == self.r.macro_def(ctxt) {
+                    // If an invocation of this macro created `ident`, give up on `ident`
+                    // and switch to `ident`'s source from the macro definition.
+                    ctxt.remove_mark();
+                    continue;
+                }
+
                 // Items in scope
                 if let RibKind::ModuleRibKind(module) = rib.kind {
                     // Items from this module
-                    self.r.add_module_candidates(module, &mut names, &filter_fn);
+                    self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt));
 
                     if let ModuleKind::Block = module.kind {
                         // We can see through blocks
@@ -1611,9 +1652,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                                             Res::Def(DefKind::Mod, crate_id.as_def_id());
 
                                         if filter_fn(crate_mod) {
-                                            Some(TypoSuggestion::typo_from_res(
-                                                ident.name, crate_mod,
-                                            ))
+                                            Some(TypoSuggestion::typo_from_ident(*ident, crate_mod))
                                         } else {
                                             None
                                         }
@@ -1622,7 +1661,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                             }));
 
                             if let Some(prelude) = self.r.prelude {
-                                self.r.add_module_candidates(prelude, &mut names, &filter_fn);
+                                self.r.add_module_candidates(prelude, &mut names, &filter_fn, None);
                             }
                         }
                         break;
@@ -1632,7 +1671,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             // Add primitive types to the mix
             if filter_fn(Res::PrimTy(PrimTy::Bool)) {
                 names.extend(PrimTy::ALL.iter().map(|prim_ty| {
-                    TypoSuggestion::typo_from_res(prim_ty.name(), Res::PrimTy(*prim_ty))
+                    TypoSuggestion::typo_from_name(prim_ty.name(), Res::PrimTy(*prim_ty))
                 }))
             }
         } else {
@@ -1641,7 +1680,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
                 self.resolve_path(mod_path, Some(TypeNS), None)
             {
-                self.r.add_module_candidates(module, &mut names, &filter_fn);
+                self.r.add_module_candidates(module, &mut names, &filter_fn, None);
             }
         }
 
@@ -1654,10 +1693,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             name,
             None,
         ) {
-            Some(found) if found != name => {
-                names.into_iter().find(|suggestion| suggestion.candidate == found)
+            Some(found) => {
+                let Some(sugg) = names.into_iter().find(|suggestion| suggestion.candidate == found) else {
+                    return TypoCandidate::None;
+                };
+                if found == name {
+                    TypoCandidate::Shadowed(sugg.res, sugg.span)
+                } else {
+                    TypoCandidate::Typo(sugg)
+                }
             }
-            _ => None,
+            _ => TypoCandidate::None,
         }
     }
 
@@ -1727,26 +1773,16 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                             }
                         }
                         if let Ok(base_snippet) = base_snippet {
-                            let mut sp = after_colon_sp;
-                            for _ in 0..100 {
-                                // Try to find an assignment
-                                sp = sm.next_point(sp);
-                                let snippet = sm.span_to_snippet(sp.to(sm.next_point(sp)));
-                                match snippet {
-                                    Ok(ref x) if x.as_str() == "=" => {
-                                        err.span_suggestion(
-                                            base_span,
-                                            "maybe you meant to write an assignment here",
-                                            format!("let {}", base_snippet),
-                                            Applicability::MaybeIncorrect,
-                                        );
-                                        show_label = false;
-                                        break;
-                                    }
-                                    Ok(ref x) if x.as_str() == "\n" => break,
-                                    Err(_) => break,
-                                    Ok(_) => {}
-                                }
+                            // Try to find an assignment
+                            let eq_span = sm.span_look_ahead(after_colon_sp, Some("="), Some(50));
+                            if let Ok(ref snippet) = sm.span_to_snippet(eq_span) && snippet == "=" {
+                                err.span_suggestion(
+                                    base_span,
+                                    "maybe you meant to write an assignment here",
+                                    format!("let {}", base_snippet),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                show_label = false;
                             }
                         }
                     }
@@ -1763,6 +1799,31 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         false
     }
 
+    fn let_binding_suggestion(&self, err: &mut Diagnostic, ident_span: Span) -> bool {
+        // try to give a suggestion for this pattern: `name = 1`, which is common in other languages
+        let mut added_suggestion = false;
+        if let Some(Expr { kind: ExprKind::Assign(lhs, _rhs, _), .. }) = self.diagnostic_metadata.in_assignment &&
+            let ast::ExprKind::Path(None, _) = lhs.kind {
+                let sm = self.r.session.source_map();
+                let line_span = sm.span_extend_to_line(ident_span);
+                let ident_name = sm.span_to_snippet(ident_span).unwrap();
+                // HACK(chenyukang): make sure ident_name is at the starting of the line to protect against macros
+                if sm
+                    .span_to_snippet(line_span)
+                    .map_or(false, |s| s.trim().starts_with(&ident_name))
+                {
+                    err.span_suggestion_verbose(
+                        ident_span.shrink_to_lo(),
+                        "you might have meant to introduce a new binding",
+                        "let ".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                    added_suggestion = true;
+                }
+            }
+        added_suggestion
+    }
+
     fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
         let mut result = None;
         let mut seen_modules = FxHashSet::default();
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 971cd62831d..ee1c97d5ad2 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -7,6 +7,7 @@
 //! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(drain_filter)]
 #![feature(if_let_guard)]
@@ -40,11 +41,12 @@ use rustc_hir::TraitCandidate;
 use rustc_index::vec::IndexVec;
 use rustc_metadata::creader::{CStore, CrateLoader};
 use rustc_middle::metadata::ModChild;
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::span_bug;
-use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, ResolverOutputs};
+use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools};
+use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs};
 use rustc_query_system::ich::StableHashingContext;
-use rustc_session::cstore::{CrateStore, CrateStoreDyn, MetadataLoaderDyn};
+use rustc_session::cstore::{CrateStore, MetadataLoaderDyn};
 use rustc_session::lint::LintBuffer;
 use rustc_session::Session;
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
@@ -62,15 +64,15 @@ use imports::{Import, ImportKind, ImportResolver, NameResolution};
 use late::{HasGenericParams, PathSource, PatternSource};
 use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 
-use crate::access_levels::AccessLevelsVisitor;
+use crate::effective_visibilities::EffectiveVisibilitiesVisitor;
 
 type Res = def::Res<NodeId>;
 
-mod access_levels;
 mod build_reduced_graph;
 mod check_unused;
 mod def_collector;
 mod diagnostics;
+mod effective_visibilities;
 mod ident;
 mod imports;
 mod late;
@@ -102,9 +104,7 @@ enum Scope<'a> {
     DeriveHelpersCompat,
     MacroRules(MacroRulesScopeRef<'a>),
     CrateRoot,
-    // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
-    // lint if it should be reported.
-    Module(Module<'a>, Option<NodeId>),
+    Module(Module<'a>),
     MacroUsePrelude,
     BuiltinAttrs,
     ExternPrelude,
@@ -644,7 +644,7 @@ impl<'a> ToNameBinding<'a> for &'a NameBinding<'a> {
 
 #[derive(Clone, Debug)]
 enum NameBindingKind<'a> {
-    Res(Res, /* is_macro_export */ bool),
+    Res(Res),
     Module(Module<'a>),
     Import { binding: &'a NameBinding<'a>, import: &'a Import<'a>, used: Cell<bool> },
 }
@@ -743,7 +743,7 @@ impl<'a> NameBinding<'a> {
 
     fn res(&self) -> Res {
         match self.kind {
-            NameBindingKind::Res(res, _) => res,
+            NameBindingKind::Res(res) => res,
             NameBindingKind::Module(module) => module.res().unwrap(),
             NameBindingKind::Import { binding, .. } => binding.res(),
         }
@@ -760,10 +760,10 @@ impl<'a> NameBinding<'a> {
     fn is_possibly_imported_variant(&self) -> bool {
         match self.kind {
             NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(),
-            NameBindingKind::Res(
-                Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _),
+            NameBindingKind::Res(Res::Def(
+                DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..),
                 _,
-            ) => true,
+            )) => true,
             NameBindingKind::Res(..) | NameBindingKind::Module(..) => false,
         }
     }
@@ -786,6 +786,13 @@ impl<'a> NameBinding<'a> {
         matches!(self.kind, NameBindingKind::Import { .. })
     }
 
+    /// The binding introduced by `#[macro_export] macro_rules` is a public import, but it might
+    /// not be perceived as such by users, so treat it as a non-import in some diagnostics.
+    fn is_import_user_facing(&self) -> bool {
+        matches!(self.kind, NameBindingKind::Import { import, .. }
+            if !matches!(import.kind, ImportKind::MacroExport))
+    }
+
     fn is_glob_import(&self) -> bool {
         match self.kind {
             NameBindingKind::Import { import, .. } => import.is_glob(),
@@ -1029,7 +1036,7 @@ pub struct Resolver<'a> {
     proc_macros: Vec<NodeId>,
     confused_type_with_std_module: FxHashMap<Span, Span>,
 
-    access_levels: AccessLevels,
+    effective_visibilities: EffectiveVisibilities,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1281,7 +1288,7 @@ impl<'a> Resolver<'a> {
 
             arenas,
             dummy_binding: arenas.alloc_name_binding(NameBinding {
-                kind: NameBindingKind::Res(Res::Err, false),
+                kind: NameBindingKind::Res(Res::Err),
                 ambiguity: None,
                 expansion: LocalExpnId::ROOT,
                 span: DUMMY_SP,
@@ -1333,7 +1340,7 @@ impl<'a> Resolver<'a> {
             trait_impls: Default::default(),
             proc_macros: Default::default(),
             confused_type_with_std_module: Default::default(),
-            access_levels: Default::default(),
+            effective_visibilities: Default::default(),
         };
 
         let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1376,9 +1383,7 @@ impl<'a> Resolver<'a> {
         Default::default()
     }
 
-    pub fn into_outputs(
-        self,
-    ) -> (Definitions, Box<CrateStoreDyn>, ResolverOutputs, ty::ResolverAstLowering) {
+    pub fn into_outputs(self) -> ResolverOutputs {
         let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
         let definitions = self.definitions;
         let cstore = Box::new(self.crate_loader.into_cstore());
@@ -1393,13 +1398,14 @@ impl<'a> Resolver<'a> {
         let glob_map = self.glob_map;
         let main_def = self.main_def;
         let confused_type_with_std_module = self.confused_type_with_std_module;
-        let access_levels = self.access_levels;
-        let resolutions = ResolverOutputs {
+        let effective_visibilities = self.effective_visibilities;
+        let global_ctxt = ResolverGlobalCtxt {
+            cstore,
             source_span,
             expn_that_defined,
             visibilities,
             has_pub_restricted,
-            access_levels,
+            effective_visibilities,
             extern_crate_map,
             reexport_map,
             glob_map,
@@ -1416,7 +1422,7 @@ impl<'a> Resolver<'a> {
             confused_type_with_std_module,
             registered_tools: self.registered_tools,
         };
-        let resolutions_lowering = ty::ResolverAstLowering {
+        let ast_lowering = ty::ResolverAstLowering {
             legacy_const_generic_args: self.legacy_const_generic_args,
             partial_res_map: self.partial_res_map,
             import_res_map: self.import_res_map,
@@ -1429,16 +1435,15 @@ impl<'a> Resolver<'a> {
             trait_map: self.trait_map,
             builtin_macro_kinds: self.builtin_macro_kinds,
         };
-        (definitions, cstore, resolutions, resolutions_lowering)
+        ResolverOutputs { definitions, global_ctxt, ast_lowering }
     }
 
-    pub fn clone_outputs(
-        &self,
-    ) -> (Definitions, Box<CrateStoreDyn>, ResolverOutputs, ty::ResolverAstLowering) {
+    pub fn clone_outputs(&self) -> ResolverOutputs {
         let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
         let definitions = self.definitions.clone();
         let cstore = Box::new(self.cstore().clone());
-        let resolutions = ResolverOutputs {
+        let global_ctxt = ResolverGlobalCtxt {
+            cstore,
             source_span: self.source_span.clone(),
             expn_that_defined: self.expn_that_defined.clone(),
             visibilities: self.visibilities.clone(),
@@ -1458,9 +1463,9 @@ impl<'a> Resolver<'a> {
             proc_macros,
             confused_type_with_std_module: self.confused_type_with_std_module.clone(),
             registered_tools: self.registered_tools.clone(),
-            access_levels: self.access_levels.clone(),
+            effective_visibilities: self.effective_visibilities.clone(),
         };
-        let resolutions_lowering = ty::ResolverAstLowering {
+        let ast_lowering = ty::ResolverAstLowering {
             legacy_const_generic_args: self.legacy_const_generic_args.clone(),
             partial_res_map: self.partial_res_map.clone(),
             import_res_map: self.import_res_map.clone(),
@@ -1473,7 +1478,7 @@ impl<'a> Resolver<'a> {
             trait_map: self.trait_map.clone(),
             builtin_macro_kinds: self.builtin_macro_kinds.clone(),
         };
-        (definitions, cstore, resolutions, resolutions_lowering)
+        ResolverOutputs { definitions, global_ctxt, ast_lowering }
     }
 
     fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
@@ -1521,8 +1526,8 @@ impl<'a> Resolver<'a> {
     pub fn resolve_crate(&mut self, krate: &Crate) {
         self.session.time("resolve_crate", || {
             self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports());
-            self.session.time("resolve_access_levels", || {
-                AccessLevelsVisitor::compute_access_levels(self, krate)
+            self.session.time("compute_effective_visibilities", || {
+                EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate)
             });
             self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
             self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
@@ -1551,7 +1556,7 @@ impl<'a> Resolver<'a> {
 
         self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| {
             match scope {
-                Scope::Module(module, _) => {
+                Scope::Module(module) => {
                     this.traits_in_module(module, assoc_item, &mut found_traits);
                 }
                 Scope::StdLibPrelude => {
@@ -1613,10 +1618,12 @@ impl<'a> Resolver<'a> {
     ) -> SmallVec<[LocalDefId; 1]> {
         let mut import_ids = smallvec![];
         while let NameBindingKind::Import { import, binding, .. } = kind {
-            let id = self.local_def_id(import.id);
-            self.maybe_unused_trait_imports.insert(id);
+            if let Some(node_id) = import.id() {
+                let def_id = self.local_def_id(node_id);
+                self.maybe_unused_trait_imports.insert(def_id);
+                import_ids.push(def_id);
+            }
             self.add_to_glob_map(&import, trait_name);
-            import_ids.push(id);
             kind = &binding.kind;
         }
         import_ids
@@ -1683,7 +1690,9 @@ impl<'a> Resolver<'a> {
             }
             used.set(true);
             import.used.set(true);
-            self.used_imports.insert(import.id);
+            if let Some(id) = import.id() {
+                self.used_imports.insert(id);
+            }
             self.add_to_glob_map(&import, ident);
             self.record_use(ident, binding, false);
         }
@@ -1691,8 +1700,8 @@ impl<'a> Resolver<'a> {
 
     #[inline]
     fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) {
-        if import.is_glob() {
-            let def_id = self.local_def_id(import.id);
+        if let ImportKind::Glob { id, .. } = import.kind {
+            let def_id = self.local_def_id(id);
             self.glob_map.entry(def_id).or_default().insert(ident.name);
         }
     }
@@ -1994,11 +2003,7 @@ impl<'a> Resolver<'a> {
 
     // Items that go to reexport table encoded to metadata and visible through it to other crates.
     fn is_reexport(&self, binding: &NameBinding<'a>) -> Option<def::Res<!>> {
-        // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules`
-        // into the crate root to actual `NameBindingKind::Import`.
-        if binding.is_import()
-            || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true))
-        {
+        if binding.is_import() {
             let res = binding.res().expect_non_local();
             // Ambiguous imports are treated as errors at this point and are
             // not exposed to other crates (see #36837 for more details).
@@ -2060,7 +2065,7 @@ struct Finalize {
     /// Span of the whole path or some its characteristic fragment.
     /// E.g. span of `b` in `foo::{a, b, c}`, or full span for regular paths.
     path_span: Span,
-    /// Span of the path start, suitable for prepending something to to it.
+    /// Span of the path start, suitable for prepending something to it.
     /// E.g. span of `foo` in `foo::{a, b, c}`, or full span for regular paths.
     root_span: Span,
     /// Whether to report privacy errors or silently return "no resolution" for them,
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index f6f0b3c1139..9526296f951 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -12,7 +12,7 @@ use rustc_attr::StabilityLevel;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand};
 use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::compile_declarative_macro;
@@ -694,7 +694,19 @@ impl<'a> Resolver<'a> {
                     check_consistency(self, &path, path_span, kind, initial_res, res)
                 }
                 path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => {
+                    let mut suggestion = None;
                     let (span, label) = if let PathResult::Failed { span, label, .. } = path_res {
+                        // try to suggest if it's not a macro, maybe a function
+                        if let PathResult::NonModule(partial_res) = self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope)
+                            && partial_res.unresolved_segments() == 0 {
+                            let sm = self.session.source_map();
+                            let exclamation_span = sm.next_point(span);
+                            suggestion = Some((
+                                vec![(exclamation_span, "".to_string())],
+                                    format!("{} is not a macro, but a {}, try to remove `!`", Segment::names_to_string(&path), partial_res.base_res().descr()),
+                                    Applicability::MaybeIncorrect
+                                ));
+                        }
                         (span, label)
                     } else {
                         (
@@ -708,7 +720,7 @@ impl<'a> Resolver<'a> {
                     };
                     self.report_error(
                         span,
-                        ResolutionError::FailedToResolve { label, suggestion: None },
+                        ResolutionError::FailedToResolve { label, suggestion },
                     );
                 }
                 PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 23d06d8e516..df5d992f663 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -57,7 +57,7 @@ macro_rules! access_from {
     ($save_ctxt:expr, $id:expr) => {
         Access {
             public: $save_ctxt.tcx.visibility($id).is_public(),
-            reachable: $save_ctxt.access_levels.is_reachable($id),
+            reachable: $save_ctxt.effective_visibilities.is_reachable($id),
         }
     };
 }
@@ -345,14 +345,14 @@ impl<'tcx> DumpVisitor<'tcx> {
         body: hir::BodyId,
     ) {
         let map = self.tcx.hir();
-        self.nest_typeck_results(item.def_id.def_id, |v| {
+        self.nest_typeck_results(item.owner_id.def_id, |v| {
             let body = map.body(body);
             if let Some(fn_data) = v.save_ctxt.get_item_data(item) {
                 down_cast_data!(fn_data, DefData, item.span);
                 v.process_formals(body.params, &fn_data.qualname);
                 v.process_generic_params(ty_params, &fn_data.qualname, item.hir_id());
 
-                v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id.def_id), fn_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item.owner_id.def_id), fn_data);
             }
 
             for arg in decl.inputs {
@@ -373,10 +373,10 @@ impl<'tcx> DumpVisitor<'tcx> {
         typ: &'tcx hir::Ty<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
     ) {
-        self.nest_typeck_results(item.def_id.def_id, |v| {
+        self.nest_typeck_results(item.owner_id.def_id, |v| {
             if let Some(var_data) = v.save_ctxt.get_item_data(item) {
                 down_cast_data!(var_data, DefData, item.span);
-                v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id.def_id), var_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item.owner_id.def_id), var_data);
             }
             v.visit_ty(&typ);
             v.visit_expr(expr);
@@ -436,7 +436,7 @@ impl<'tcx> DumpVisitor<'tcx> {
     ) {
         debug!("process_struct {:?} {:?}", item, item.span);
         let name = item.ident.to_string();
-        let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
+        let qualname = format!("::{}", self.tcx.def_path_str(item.owner_id.to_def_id()));
 
         let kind = match item.kind {
             hir::ItemKind::Struct(_, _) => DefKind::Struct,
@@ -473,10 +473,10 @@ impl<'tcx> DumpVisitor<'tcx> {
             let span = self.span_from_span(item.ident.span);
             let attrs = self.tcx.hir().attrs(item.hir_id());
             self.dumper.dump_def(
-                &access_from!(self.save_ctxt, item.def_id.def_id),
+                &access_from!(self.save_ctxt, item.owner_id.def_id),
                 Def {
                     kind,
-                    id: id_from_def_id(item.def_id.to_def_id()),
+                    id: id_from_def_id(item.owner_id.to_def_id()),
                     span,
                     name,
                     qualname: qualname.clone(),
@@ -491,7 +491,7 @@ impl<'tcx> DumpVisitor<'tcx> {
             );
         }
 
-        self.nest_typeck_results(item.def_id.def_id, |v| {
+        self.nest_typeck_results(item.owner_id.def_id, |v| {
             for field in def.fields() {
                 v.process_struct_field_def(field, item.hir_id());
                 v.visit_ty(&field.ty);
@@ -513,7 +513,7 @@ impl<'tcx> DumpVisitor<'tcx> {
         };
         down_cast_data!(enum_data, DefData, item.span);
 
-        let access = access_from!(self.save_ctxt, item.def_id.def_id);
+        let access = access_from!(self.save_ctxt, item.owner_id.def_id);
 
         for variant in enum_definition.variants {
             let name = variant.ident.name.to_string();
@@ -528,7 +528,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                     if !self.span.filter_generated(name_span) {
                         let span = self.span_from_span(name_span);
                         let id = id_from_hir_id(variant.id, &self.save_ctxt);
-                        let parent = Some(id_from_def_id(item.def_id.to_def_id()));
+                        let parent = Some(id_from_def_id(item.owner_id.to_def_id()));
                         let attrs = self.tcx.hir().attrs(variant.id);
 
                         self.dumper.dump_def(
@@ -566,7 +566,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                     if !self.span.filter_generated(name_span) {
                         let span = self.span_from_span(name_span);
                         let id = id_from_hir_id(variant.id, &self.save_ctxt);
-                        let parent = Some(id_from_def_id(item.def_id.to_def_id()));
+                        let parent = Some(id_from_def_id(item.owner_id.to_def_id()));
                         let attrs = self.tcx.hir().attrs(variant.id);
 
                         self.dumper.dump_def(
@@ -612,14 +612,14 @@ impl<'tcx> DumpVisitor<'tcx> {
         }
 
         let map = self.tcx.hir();
-        self.nest_typeck_results(item.def_id.def_id, |v| {
+        self.nest_typeck_results(item.owner_id.def_id, |v| {
             v.visit_ty(&impl_.self_ty);
             if let Some(trait_ref) = &impl_.of_trait {
                 v.process_path(trait_ref.hir_ref_id, &hir::QPath::Resolved(None, &trait_ref.path));
             }
             v.process_generic_params(&impl_.generics, "", item.hir_id());
             for impl_item in impl_.items {
-                v.process_impl_item(map.impl_item(impl_item.id), item.def_id.to_def_id());
+                v.process_impl_item(map.impl_item(impl_item.id), item.owner_id.to_def_id());
             }
         });
     }
@@ -632,7 +632,7 @@ impl<'tcx> DumpVisitor<'tcx> {
         methods: &'tcx [hir::TraitItemRef],
     ) {
         let name = item.ident.to_string();
-        let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
+        let qualname = format!("::{}", self.tcx.def_path_str(item.owner_id.to_def_id()));
         let mut val = name.clone();
         if !generics.params.is_empty() {
             val.push_str(&generic_params_to_string(generics.params));
@@ -642,13 +642,13 @@ impl<'tcx> DumpVisitor<'tcx> {
             val.push_str(&bounds_to_string(trait_refs));
         }
         if !self.span.filter_generated(item.ident.span) {
-            let id = id_from_def_id(item.def_id.to_def_id());
+            let id = id_from_def_id(item.owner_id.to_def_id());
             let span = self.span_from_span(item.ident.span);
             let children =
-                methods.iter().map(|i| id_from_def_id(i.id.def_id.to_def_id())).collect();
+                methods.iter().map(|i| id_from_def_id(i.id.owner_id.to_def_id())).collect();
             let attrs = self.tcx.hir().attrs(item.hir_id());
             self.dumper.dump_def(
-                &access_from!(self.save_ctxt, item.def_id.def_id),
+                &access_from!(self.save_ctxt, item.owner_id.def_id),
                 Def {
                     kind: DefKind::Trait,
                     id,
@@ -692,7 +692,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                         kind: RelationKind::SuperTrait,
                         span,
                         from: id_from_def_id(id),
-                        to: id_from_def_id(item.def_id.to_def_id()),
+                        to: id_from_def_id(item.owner_id.to_def_id()),
                     });
                 }
             }
@@ -702,7 +702,7 @@ impl<'tcx> DumpVisitor<'tcx> {
         self.process_generic_params(generics, &qualname, item.hir_id());
         for method in methods {
             let map = self.tcx.hir();
-            self.process_trait_item(map.trait_item(method.id), item.def_id.to_def_id())
+            self.process_trait_item(map.trait_item(method.id), item.owner_id.to_def_id())
         }
     }
 
@@ -710,7 +710,7 @@ impl<'tcx> DumpVisitor<'tcx> {
     fn process_mod(&mut self, item: &'tcx hir::Item<'tcx>) {
         if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
             down_cast_data!(mod_data, DefData, item.span);
-            self.dumper.dump_def(&access_from!(self.save_ctxt, item.def_id.def_id), mod_data);
+            self.dumper.dump_def(&access_from!(self.save_ctxt, item.owner_id.def_id), mod_data);
         }
     }
 
@@ -981,7 +981,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                 let body = body.map(|b| self.tcx.hir().body(b).value);
                 let attrs = self.tcx.hir().attrs(trait_item.hir_id());
                 self.process_assoc_const(
-                    trait_item.def_id.def_id,
+                    trait_item.owner_id.def_id,
                     trait_item.ident,
                     &ty,
                     body,
@@ -995,7 +995,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                 self.process_method(
                     sig,
                     body,
-                    trait_item.def_id.def_id,
+                    trait_item.owner_id.def_id,
                     trait_item.ident,
                     &trait_item.generics,
                     trait_item.span,
@@ -1005,11 +1005,11 @@ impl<'tcx> DumpVisitor<'tcx> {
                 // FIXME do something with _bounds (for type refs)
                 let name = trait_item.ident.name.to_string();
                 let qualname =
-                    format!("::{}", self.tcx.def_path_str(trait_item.def_id.to_def_id()));
+                    format!("::{}", self.tcx.def_path_str(trait_item.owner_id.to_def_id()));
 
                 if !self.span.filter_generated(trait_item.ident.span) {
                     let span = self.span_from_span(trait_item.ident.span);
-                    let id = id_from_def_id(trait_item.def_id.to_def_id());
+                    let id = id_from_def_id(trait_item.owner_id.to_def_id());
                     let attrs = self.tcx.hir().attrs(trait_item.hir_id());
 
                     self.dumper.dump_def(
@@ -1051,7 +1051,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                 let body = self.tcx.hir().body(body);
                 let attrs = self.tcx.hir().attrs(impl_item.hir_id());
                 self.process_assoc_const(
-                    impl_item.def_id.def_id,
+                    impl_item.owner_id.def_id,
                     impl_item.ident,
                     &ty,
                     Some(&body.value),
@@ -1063,7 +1063,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                 self.process_method(
                     sig,
                     Some(body),
-                    impl_item.def_id.def_id,
+                    impl_item.owner_id.def_id,
                     impl_item.ident,
                     &impl_item.generics,
                     impl_item.span,
@@ -1088,7 +1088,7 @@ impl<'tcx> DumpVisitor<'tcx> {
         let filename = sm.span_to_filename(krate_mod.spans.inner_span);
         let data_id = id_from_hir_id(id, &self.save_ctxt);
         let children =
-            krate_mod.item_ids.iter().map(|i| id_from_def_id(i.def_id.to_def_id())).collect();
+            krate_mod.item_ids.iter().map(|i| id_from_def_id(i.owner_id.to_def_id())).collect();
         let span = self.span_from_span(krate_mod.spans.inner_span);
         let attrs = self.tcx.hir().attrs(id);
 
@@ -1137,10 +1137,10 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
             hir::ItemKind::Use(path, hir::UseKind::Single) => {
                 let sub_span = path.segments.last().unwrap().ident.span;
                 if !self.span.filter_generated(sub_span) {
-                    let access = access_from!(self.save_ctxt, item.def_id.def_id);
+                    let access = access_from!(self.save_ctxt, item.owner_id.def_id);
                     let ref_id = self.lookup_def_id(item.hir_id()).map(id_from_def_id);
                     let span = self.span_from_span(sub_span);
-                    let parent = self.save_ctxt.tcx.local_parent(item.def_id.def_id);
+                    let parent = self.save_ctxt.tcx.local_parent(item.owner_id.def_id);
                     self.dumper.import(
                         &access,
                         Import {
@@ -1158,16 +1158,16 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
             }
             hir::ItemKind::Use(path, hir::UseKind::Glob) => {
                 // Make a comma-separated list of names of imported modules.
-                let names = self.tcx.names_imported_by_glob_use(item.def_id.def_id);
+                let names = self.tcx.names_imported_by_glob_use(item.owner_id.def_id);
                 let names: Vec<_> = names.iter().map(|n| n.to_string()).collect();
 
                 // Otherwise it's a span with wrong macro expansion info, which
                 // we don't want to track anyway, since it's probably macro-internal `use`
                 if let Some(sub_span) = self.span.sub_span_of_star(item.span) {
                     if !self.span.filter_generated(item.span) {
-                        let access = access_from!(self.save_ctxt, item.def_id.def_id);
+                        let access = access_from!(self.save_ctxt, item.owner_id.def_id);
                         let span = self.span_from_span(sub_span);
-                        let parent = self.save_ctxt.tcx.local_parent(item.def_id.def_id);
+                        let parent = self.save_ctxt.tcx.local_parent(item.owner_id.def_id);
                         self.dumper.import(
                             &access,
                             Import {
@@ -1188,7 +1188,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                 let name_span = item.ident.span;
                 if !self.span.filter_generated(name_span) {
                     let span = self.span_from_span(name_span);
-                    let parent = self.save_ctxt.tcx.local_parent(item.def_id.def_id);
+                    let parent = self.save_ctxt.tcx.local_parent(item.owner_id.def_id);
                     self.dumper.import(
                         &Access { public: false, reachable: false },
                         Import {
@@ -1228,15 +1228,15 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                 intravisit::walk_mod(self, m, item.hir_id());
             }
             hir::ItemKind::TyAlias(ty, ref generics) => {
-                let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
+                let qualname = format!("::{}", self.tcx.def_path_str(item.owner_id.to_def_id()));
                 let value = ty_to_string(&ty);
                 if !self.span.filter_generated(item.ident.span) {
                     let span = self.span_from_span(item.ident.span);
-                    let id = id_from_def_id(item.def_id.to_def_id());
+                    let id = id_from_def_id(item.owner_id.to_def_id());
                     let attrs = self.tcx.hir().attrs(item.hir_id());
 
                     self.dumper.dump_def(
-                        &access_from!(self.save_ctxt, item.def_id.def_id),
+                        &access_from!(self.save_ctxt, item.owner_id.def_id),
                         Def {
                             kind: DefKind::Type,
                             id,
@@ -1324,7 +1324,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
             }
             hir::TyKind::OpaqueDef(item_id, _, _) => {
                 let item = self.tcx.hir().item(item_id);
-                self.nest_typeck_results(item_id.def_id.def_id, |v| v.visit_item(item));
+                self.nest_typeck_results(item_id.owner_id.def_id, |v| v.visit_item(item));
             }
             _ => intravisit::walk_ty(self, t),
         }
@@ -1431,7 +1431,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
     }
 
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
-        let access = access_from!(self.save_ctxt, item.def_id.def_id);
+        let access = access_from!(self.save_ctxt, item.owner_id.def_id);
 
         match item.kind {
             hir::ForeignItemKind::Fn(decl, _, ref generics) => {
diff --git a/compiler/rustc_save_analysis/src/errors.rs b/compiler/rustc_save_analysis/src/errors.rs
index 8a15ba63661..585aac8c1c3 100644
--- a/compiler/rustc_save_analysis/src/errors.rs
+++ b/compiler/rustc_save_analysis/src/errors.rs
@@ -3,7 +3,7 @@ use rustc_macros::Diagnostic;
 use std::path::Path;
 
 #[derive(Diagnostic)]
-#[diag(save_analysis::could_not_open)]
+#[diag(save_analysis_could_not_open)]
 pub(crate) struct CouldNotOpen<'a> {
     pub file_name: &'a Path,
     pub err: std::io::Error,
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index aa000b7067b..d0155c908a2 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -26,7 +26,7 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::Node;
 use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::ty::{self, print::with_no_trimmed_paths, DefIdTree, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{CrateType, Input, OutputType};
@@ -54,7 +54,7 @@ use rls_data::{
 pub struct SaveContext<'tcx> {
     tcx: TyCtxt<'tcx>,
     maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
-    access_levels: &'tcx AccessLevels,
+    effective_visibilities: &'tcx EffectiveVisibilities,
     span_utils: SpanUtils<'tcx>,
     config: Config,
     impl_counter: Cell<u32>,
@@ -141,7 +141,7 @@ impl<'tcx> SaveContext<'tcx> {
     }
 
     pub fn get_extern_item_data(&self, item: &hir::ForeignItem<'_>) -> Option<Data> {
-        let def_id = item.def_id.to_def_id();
+        let def_id = item.owner_id.to_def_id();
         let qualname = format!("::{}", self.tcx.def_path_str(def_id));
         let attrs = self.tcx.hir().attrs(item.hir_id());
         match item.kind {
@@ -205,7 +205,7 @@ impl<'tcx> SaveContext<'tcx> {
     }
 
     pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> {
-        let def_id = item.def_id.to_def_id();
+        let def_id = item.owner_id.to_def_id();
         let attrs = self.tcx.hir().attrs(item.hir_id());
         match item.kind {
             hir::ItemKind::Fn(ref sig, ref generics, _) => {
@@ -297,7 +297,7 @@ impl<'tcx> SaveContext<'tcx> {
                     children: m
                         .item_ids
                         .iter()
-                        .map(|i| id_from_def_id(i.def_id.to_def_id()))
+                        .map(|i| id_from_def_id(i.owner_id.to_def_id()))
                         .collect(),
                     decl_id: None,
                     docs: self.docs_for_attrs(attrs),
@@ -363,7 +363,7 @@ impl<'tcx> SaveContext<'tcx> {
                             parent: None,
                             children: items
                                 .iter()
-                                .map(|i| id_from_def_id(i.id.def_id.to_def_id()))
+                                .map(|i| id_from_def_id(i.id.owner_id.to_def_id()))
                                 .collect(),
                             docs: String::new(),
                             sig: None,
@@ -968,16 +968,16 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(
             info!("Dumping crate {}", cratename);
 
             // Privacy checking must be done outside of type inference; use a
-            // fallback in case the access levels couldn't have been correctly computed.
-            let access_levels = match tcx.sess.compile_status() {
-                Ok(..) => tcx.privacy_access_levels(()),
-                Err(..) => tcx.arena.alloc(AccessLevels::default()),
+            // fallback in case effective visibilities couldn't have been correctly computed.
+            let effective_visibilities = match tcx.sess.compile_status() {
+                Ok(..) => tcx.effective_visibilities(()),
+                Err(..) => tcx.arena.alloc(EffectiveVisibilities::default()),
             };
 
             let save_ctxt = SaveContext {
                 tcx,
                 maybe_typeck_results: None,
-                access_levels: &access_levels,
+                effective_visibilities: &effective_visibilities,
                 span_utils: SpanUtils::new(&tcx.sess),
                 config: find_config(config),
                 impl_counter: Cell::new(0),
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index 62e9f6520fb..83c51d213be 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -337,7 +337,7 @@ impl<'hir> Sig for hir::Item<'hir> {
                 }
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_def_id(self.def_id.to_def_id()),
+                    id: id_from_def_id(self.owner_id.to_def_id()),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -359,7 +359,7 @@ impl<'hir> Sig for hir::Item<'hir> {
                 let mut text = "const ".to_owned();
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_def_id(self.def_id.to_def_id()),
+                    id: id_from_def_id(self.owner_id.to_def_id()),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -428,7 +428,7 @@ impl<'hir> Sig for hir::Item<'hir> {
                 let mut text = "mod ".to_owned();
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_def_id(self.def_id.to_def_id()),
+                    id: id_from_def_id(self.owner_id.to_def_id()),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -764,7 +764,7 @@ impl<'hir> Sig for hir::ForeignItem<'hir> {
                 }
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_def_id(self.def_id.to_def_id()),
+                    id: id_from_def_id(self.owner_id.to_def_id()),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -780,7 +780,7 @@ impl<'hir> Sig for hir::ForeignItem<'hir> {
                 let mut text = "type ".to_owned();
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_def_id(self.def_id.to_def_id()),
+                    id: id_from_def_id(self.owner_id.to_def_id()),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml
index 3b0b3144f2c..db0ef73544f 100644
--- a/compiler/rustc_serialize/Cargo.toml
+++ b/compiler/rustc_serialize/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 [dependencies]
 indexmap = "1.9.1"
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
 
 [dev-dependencies]
 rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 70b470f3811..b8ad18c64dc 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3,7 +3,6 @@
 
 pub use crate::options::*;
 
-use crate::errors::TargetDataLayoutErrorsWrapper;
 use crate::search_paths::SearchPath;
 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
 use crate::{early_error, early_warn, Session};
@@ -739,7 +738,7 @@ impl Default for Options {
             actually_rustdoc: false,
             trimmed_def_paths: TrimmedDefPaths::default(),
             cli_forced_codegen_units: None,
-            cli_forced_thinlto_off: false,
+            cli_forced_local_thinlto_off: false,
             remap_path_prefix: Vec::new(),
             real_rust_source_base_dir: None,
             edition: DEFAULT_EDITION,
@@ -795,6 +794,7 @@ impl UnstableOptions {
             report_delayed_bugs: self.report_delayed_bugs,
             macro_backtrace: self.macro_backtrace,
             deduplicate_diagnostics: self.deduplicate_diagnostics,
+            track_diagnostics: self.track_diagnostics,
         }
     }
 }
@@ -900,7 +900,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
     let max_atomic_width = sess.target.max_atomic_width();
     let atomic_cas = sess.target.atomic_cas;
     let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
-        sess.emit_fatal(TargetDataLayoutErrorsWrapper(err));
+        sess.emit_fatal(err);
     });
 
     let mut ret = CrateConfig::default();
@@ -1721,7 +1721,7 @@ fn should_override_cgus_and_disable_thinlto(
     error_format: ErrorOutputType,
     mut codegen_units: Option<usize>,
 ) -> (bool, Option<usize>) {
-    let mut disable_thinlto = false;
+    let mut disable_local_thinlto = false;
     // Issue #30063: if user requests LLVM-related output to one
     // particular path, disable codegen-units.
     let incompatible: Vec<_> = output_types
@@ -1746,12 +1746,12 @@ fn should_override_cgus_and_disable_thinlto(
                     }
                     early_warn(error_format, "resetting to default -C codegen-units=1");
                     codegen_units = Some(1);
-                    disable_thinlto = true;
+                    disable_local_thinlto = true;
                 }
             }
             _ => {
                 codegen_units = Some(1);
-                disable_thinlto = true;
+                disable_local_thinlto = true;
             }
         }
     }
@@ -1760,7 +1760,7 @@ fn should_override_cgus_and_disable_thinlto(
         early_error(error_format, "value for codegen units must be a positive non-zero integer");
     }
 
-    (disable_thinlto, codegen_units)
+    (disable_local_thinlto, codegen_units)
 }
 
 fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
@@ -1789,34 +1789,49 @@ fn collect_print_requests(
         cg.target_feature = String::new();
     }
 
-    prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
-        "crate-name" => PrintRequest::CrateName,
-        "file-names" => PrintRequest::FileNames,
-        "sysroot" => PrintRequest::Sysroot,
-        "target-libdir" => PrintRequest::TargetLibdir,
-        "cfg" => PrintRequest::Cfg,
-        "calling-conventions" => PrintRequest::CallingConventions,
-        "target-list" => PrintRequest::TargetList,
-        "target-cpus" => PrintRequest::TargetCPUs,
-        "target-features" => PrintRequest::TargetFeatures,
-        "relocation-models" => PrintRequest::RelocationModels,
-        "code-models" => PrintRequest::CodeModels,
-        "tls-models" => PrintRequest::TlsModels,
-        "native-static-libs" => PrintRequest::NativeStaticLibs,
-        "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
-        "target-spec-json" => {
-            if unstable_opts.unstable_options {
-                PrintRequest::TargetSpec
-            } else {
+    const PRINT_REQUESTS: &[(&str, PrintRequest)] = &[
+        ("crate-name", PrintRequest::CrateName),
+        ("file-names", PrintRequest::FileNames),
+        ("sysroot", PrintRequest::Sysroot),
+        ("target-libdir", PrintRequest::TargetLibdir),
+        ("cfg", PrintRequest::Cfg),
+        ("calling-conventions", PrintRequest::CallingConventions),
+        ("target-list", PrintRequest::TargetList),
+        ("target-cpus", PrintRequest::TargetCPUs),
+        ("target-features", PrintRequest::TargetFeatures),
+        ("relocation-models", PrintRequest::RelocationModels),
+        ("code-models", PrintRequest::CodeModels),
+        ("tls-models", PrintRequest::TlsModels),
+        ("native-static-libs", PrintRequest::NativeStaticLibs),
+        ("stack-protector-strategies", PrintRequest::StackProtectorStrategies),
+        ("target-spec-json", PrintRequest::TargetSpec),
+        ("link-args", PrintRequest::LinkArgs),
+    ];
+
+    prints.extend(matches.opt_strs("print").into_iter().map(|req| {
+        match PRINT_REQUESTS.iter().find(|&&(name, _)| name == req) {
+            Some((_, PrintRequest::TargetSpec)) => {
+                if unstable_opts.unstable_options {
+                    PrintRequest::TargetSpec
+                } else {
+                    early_error(
+                        error_format,
+                        "the `-Z unstable-options` flag must also be passed to \
+                     enable the target-spec-json print option",
+                    );
+                }
+            }
+            Some(&(_, print_request)) => print_request,
+            None => {
+                let prints =
+                    PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
+                let prints = prints.join(", ");
                 early_error(
                     error_format,
-                    "the `-Z unstable-options` flag must also be passed to \
-                     enable the target-spec-json print option",
+                    &format!("unknown print request `{req}`. Valid print requests are: {prints}"),
                 );
             }
         }
-        "link-args" => PrintRequest::LinkArgs,
-        req => early_error(error_format, &format!("unknown print request `{req}`")),
     }));
 
     prints
@@ -2250,7 +2265,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     let output_types = parse_output_types(&unstable_opts, matches, error_format);
 
     let mut cg = CodegenOptions::build(matches, error_format);
-    let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
+    let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
         &output_types,
         matches,
         error_format,
@@ -2493,7 +2508,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         actually_rustdoc: false,
         trimmed_def_paths: TrimmedDefPaths::default(),
         cli_forced_codegen_units: codegen_units,
-        cli_forced_thinlto_off: disable_thinlto,
+        cli_forced_local_thinlto_off: disable_local_thinlto,
         remap_path_prefix,
         real_rust_source_base_dir,
         edition,
diff --git a/compiler/rustc_session/src/config/sigpipe.rs b/compiler/rustc_session/src/config/sigpipe.rs
index a5c94118a47..53692ad7cc9 100644
--- a/compiler/rustc_session/src/config/sigpipe.rs
+++ b/compiler/rustc_session/src/config/sigpipe.rs
@@ -1,5 +1,13 @@
 //! NOTE: Keep these constants in sync with `library/std/src/sys/unix/mod.rs`!
 
+/// The default value if `#[unix_sigpipe]` is not specified. This resolves
+/// to `SIG_IGN` in `library/std/src/sys/unix/mod.rs`.
+///
+/// Note that `SIG_IGN` has been the Rust default since 2014. See
+/// <https://github.com/rust-lang/rust/issues/62569>.
+#[allow(dead_code)]
+pub const DEFAULT: u8 = 0;
+
 /// Do not touch `SIGPIPE`. Use whatever the parent process uses.
 #[allow(dead_code)]
 pub const INHERIT: u8 = 1;
@@ -15,8 +23,3 @@ pub const SIG_IGN: u8 = 2;
 /// such as `head -n 1`.
 #[allow(dead_code)]
 pub const SIG_DFL: u8 = 3;
-
-/// `SIG_IGN` has been the Rust default since 2014. See
-/// <https://github.com/rust-lang/rust/issues/62569>.
-#[allow(dead_code)]
-pub const DEFAULT: u8 = SIG_IGN;
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index b5962f76b7f..bf542faec41 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -1,16 +1,13 @@
 use std::num::NonZeroU32;
 
 use crate::cgu_reuse_tracker::CguReuse;
-use rustc_errors::{
-    fluent, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan,
-};
+use rustc_errors::MultiSpan;
 use rustc_macros::Diagnostic;
 use rustc_span::{Span, Symbol};
-use rustc_target::abi::TargetDataLayoutErrors;
 use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
 
 #[derive(Diagnostic)]
-#[diag(session::incorrect_cgu_reuse_type)]
+#[diag(session_incorrect_cgu_reuse_type)]
 pub struct IncorrectCguReuseType<'a> {
     #[primary_span]
     pub span: Span,
@@ -21,14 +18,14 @@ pub struct IncorrectCguReuseType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(session::cgu_not_recorded)]
+#[diag(session_cgu_not_recorded)]
 pub struct CguNotRecorded<'a> {
     pub cgu_user_name: &'a str,
     pub cgu_name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::feature_gate_error, code = "E0658")]
+#[diag(session_feature_gate_error, code = "E0658")]
 pub struct FeatureGateError<'a> {
     #[primary_span]
     pub span: MultiSpan,
@@ -36,152 +33,99 @@ pub struct FeatureGateError<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[note(session::feature_diagnostic_for_issue)]
+#[note(session_feature_diagnostic_for_issue)]
 pub struct FeatureDiagnosticForIssue {
     pub n: NonZeroU32,
 }
 
 #[derive(Subdiagnostic)]
-#[help(session::feature_diagnostic_help)]
+#[help(session_feature_diagnostic_help)]
 pub struct FeatureDiagnosticHelp {
     pub feature: Symbol,
 }
 
-pub struct TargetDataLayoutErrorsWrapper<'a>(pub TargetDataLayoutErrors<'a>);
-
-impl IntoDiagnostic<'_, !> for TargetDataLayoutErrorsWrapper<'_> {
-    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
-        let mut diag;
-        match self.0 {
-            TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
-                diag = handler.struct_fatal(fluent::session::target_invalid_address_space);
-                diag.set_arg("addr_space", addr_space);
-                diag.set_arg("cause", cause);
-                diag.set_arg("err", err);
-                diag
-            }
-            TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
-                diag = handler.struct_fatal(fluent::session::target_invalid_bits);
-                diag.set_arg("kind", kind);
-                diag.set_arg("bit", bit);
-                diag.set_arg("cause", cause);
-                diag.set_arg("err", err);
-                diag
-            }
-            TargetDataLayoutErrors::MissingAlignment { cause } => {
-                diag = handler.struct_fatal(fluent::session::target_missing_alignment);
-                diag.set_arg("cause", cause);
-                diag
-            }
-            TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
-                diag = handler.struct_fatal(fluent::session::target_invalid_alignment);
-                diag.set_arg("cause", cause);
-                diag.set_arg("err", err);
-                diag
-            }
-            TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
-                diag = handler.struct_fatal(fluent::session::target_inconsistent_architecture);
-                diag.set_arg("dl", dl);
-                diag.set_arg("target", target);
-                diag
-            }
-            TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
-                diag = handler.struct_fatal(fluent::session::target_inconsistent_pointer_width);
-                diag.set_arg("pointer_size", pointer_size);
-                diag.set_arg("target", target);
-                diag
-            }
-            TargetDataLayoutErrors::InvalidBitsSize { err } => {
-                diag = handler.struct_fatal(fluent::session::target_invalid_bits_size);
-                diag.set_arg("err", err);
-                diag
-            }
-        }
-    }
-}
-
 #[derive(Diagnostic)]
-#[diag(session::not_circumvent_feature)]
+#[diag(session_not_circumvent_feature)]
 pub struct NotCircumventFeature;
 
 #[derive(Diagnostic)]
-#[diag(session::linker_plugin_lto_windows_not_supported)]
+#[diag(session_linker_plugin_lto_windows_not_supported)]
 pub struct LinkerPluginToWindowsNotSupported;
 
 #[derive(Diagnostic)]
-#[diag(session::profile_use_file_does_not_exist)]
+#[diag(session_profile_use_file_does_not_exist)]
 pub struct ProfileUseFileDoesNotExist<'a> {
     pub path: &'a std::path::Path,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::profile_sample_use_file_does_not_exist)]
+#[diag(session_profile_sample_use_file_does_not_exist)]
 pub struct ProfileSampleUseFileDoesNotExist<'a> {
     pub path: &'a std::path::Path,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::target_requires_unwind_tables)]
+#[diag(session_target_requires_unwind_tables)]
 pub struct TargetRequiresUnwindTables;
 
 #[derive(Diagnostic)]
-#[diag(session::sanitizer_not_supported)]
+#[diag(session_sanitizer_not_supported)]
 pub struct SanitizerNotSupported {
     pub us: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::sanitizers_not_supported)]
+#[diag(session_sanitizers_not_supported)]
 pub struct SanitizersNotSupported {
     pub us: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::cannot_mix_and_match_sanitizers)]
+#[diag(session_cannot_mix_and_match_sanitizers)]
 pub struct CannotMixAndMatchSanitizers {
     pub first: String,
     pub second: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::cannot_enable_crt_static_linux)]
+#[diag(session_cannot_enable_crt_static_linux)]
 pub struct CannotEnableCrtStaticLinux;
 
 #[derive(Diagnostic)]
-#[diag(session::sanitizer_cfi_enabled)]
+#[diag(session_sanitizer_cfi_enabled)]
 pub struct SanitizerCfiEnabled;
 
 #[derive(Diagnostic)]
-#[diag(session::unstable_virtual_function_elimination)]
+#[diag(session_unstable_virtual_function_elimination)]
 pub struct UnstableVirtualFunctionElimination;
 
 #[derive(Diagnostic)]
-#[diag(session::unsupported_dwarf_version)]
+#[diag(session_unsupported_dwarf_version)]
 pub struct UnsupportedDwarfVersion {
     pub dwarf_version: u32,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::target_stack_protector_not_supported)]
+#[diag(session_target_stack_protector_not_supported)]
 pub struct StackProtectorNotSupportedForTarget<'a> {
     pub stack_protector: StackProtector,
     pub target_triple: &'a TargetTriple,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::split_debuginfo_unstable_platform)]
+#[diag(session_split_debuginfo_unstable_platform)]
 pub struct SplitDebugInfoUnstablePlatform {
     pub debuginfo: SplitDebuginfo,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::file_is_not_writeable)]
+#[diag(session_file_is_not_writeable)]
 pub struct FileIsNotWriteable<'a> {
     pub file: &'a std::path::Path,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::crate_name_does_not_match)]
+#[diag(session_crate_name_does_not_match)]
 pub struct CrateNameDoesNotMatch<'a> {
     #[primary_span]
     pub span: Span,
@@ -190,38 +134,29 @@ pub struct CrateNameDoesNotMatch<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(session::crate_name_invalid)]
+#[diag(session_crate_name_invalid)]
 pub struct CrateNameInvalid<'a> {
     pub s: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::crate_name_empty)]
+#[diag(session_crate_name_empty)]
 pub struct CrateNameEmpty {
     #[primary_span]
     pub span: Option<Span>,
 }
 
+#[derive(Diagnostic)]
+#[diag(session_invalid_character_in_create_name)]
 pub struct InvalidCharacterInCrateName<'a> {
+    #[primary_span]
     pub span: Option<Span>,
     pub character: char,
     pub crate_name: &'a str,
 }
 
-impl IntoDiagnostic<'_> for InvalidCharacterInCrateName<'_> {
-    fn into_diagnostic(self, sess: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = sess.struct_err(fluent::session::invalid_character_in_create_name);
-        if let Some(sp) = self.span {
-            diag.set_span(sp);
-        }
-        diag.set_arg("character", self.character);
-        diag.set_arg("crate_name", self.crate_name);
-        diag
-    }
-}
-
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(session::expr_parentheses_needed, applicability = "machine-applicable")]
+#[multipart_suggestion(session_expr_parentheses_needed, applicability = "machine-applicable")]
 pub struct ExprParenthesesNeeded {
     #[suggestion_part(code = "(")]
     pub left: Span,
@@ -234,3 +169,25 @@ impl ExprParenthesesNeeded {
         ExprParenthesesNeeded { left: s.shrink_to_lo(), right: s.shrink_to_hi() }
     }
 }
+
+#[derive(Diagnostic)]
+#[diag(session_skipping_const_checks)]
+pub struct SkippingConstChecks {
+    #[subdiagnostic(eager)]
+    pub unleashed_features: Vec<UnleashedFeatureHelp>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum UnleashedFeatureHelp {
+    #[help(session_unleashed_feature_help_named)]
+    Named {
+        #[primary_span]
+        span: Span,
+        gate: Symbol,
+    },
+    #[help(session_unleashed_feature_help_unnamed)]
+    Unnamed {
+        #[primary_span]
+        span: Span,
+    },
+}
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 102df3a4d7e..f9ee202466f 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -181,12 +181,12 @@ top_level_options!(
         #[rustc_lint_opt_deny_field_access("use `Session::codegen_units` instead of this field")]
         cli_forced_codegen_units: Option<usize> [UNTRACKED],
         #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
-        cli_forced_thinlto_off: bool [UNTRACKED],
+        cli_forced_local_thinlto_off: bool [UNTRACKED],
 
         /// Remap source path prefixes in all output (messages, object files, debug, etc.).
         remap_path_prefix: Vec<(PathBuf, PathBuf)> [TRACKED_NO_CRATE_HASH],
         /// Base directory containing the `src/` for the Rust standard library, and
-        /// potentially `rustc` as well, if we can can find it. Right now it's always
+        /// potentially `rustc` as well, if we can find it. Right now it's always
         /// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component).
         ///
         /// This directory is what the virtual `/rustc/$hash` is translated back to,
@@ -1295,6 +1295,8 @@ options! {
         an additional `.html` file showing the computed coverage spans."),
     dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
         "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
+    dylib_lto: bool = (false, parse_bool, [UNTRACKED],
+        "enables LTO for dylib crate type"),
     emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
         "emit a section containing stack size metadata (default: no)"),
     emit_thin_lto: bool = (true, parse_bool, [TRACKED],
@@ -1585,6 +1587,8 @@ options! {
         "choose the TLS model to use (`rustc --print tls-models` for details)"),
     trace_macros: bool = (false, parse_bool, [UNTRACKED],
         "for every macro invocation, print its name and arguments (default: no)"),
+    track_diagnostics: bool = (false, parse_bool, [UNTRACKED],
+        "tracks where in rustc a diagnostic was emitted"),
     // Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
     // alongside query results and changes to translation options can affect diagnostics - so
     // translation options should be tracked.
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index a199947ebed..f9f4f2979c4 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -97,6 +97,7 @@ pub fn feature_err<'a>(
 ///
 /// This variant allows you to control whether it is a library or language feature.
 /// Almost always, you want to use this for a language feature. If so, prefer `feature_err`.
+#[track_caller]
 pub fn feature_err_issue<'a>(
     sess: &'a ParseSess,
     feature: Symbol,
@@ -332,6 +333,7 @@ impl ParseSess {
         self.proc_macro_quoted_spans.lock().clone()
     }
 
+    #[track_caller]
     pub fn create_err<'a>(
         &'a self,
         err: impl IntoDiagnostic<'a>,
@@ -339,10 +341,12 @@ impl ParseSess {
         err.into_diagnostic(&self.span_diagnostic)
     }
 
+    #[track_caller]
     pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
         self.create_err(err).emit()
     }
 
+    #[track_caller]
     pub fn create_warning<'a>(
         &'a self,
         warning: impl IntoDiagnostic<'a, ()>,
@@ -350,6 +354,7 @@ impl ParseSess {
         warning.into_diagnostic(&self.span_diagnostic)
     }
 
+    #[track_caller]
     pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
         self.create_warning(warning).emit()
     }
@@ -377,6 +382,7 @@ impl ParseSess {
     }
 
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index beb22ab3eb9..ec0a5b9d0d8 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -5,9 +5,10 @@ use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, S
 use crate::errors::{
     CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported,
     NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist,
-    SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported,
+    SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, SkippingConstChecks,
     SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget,
-    TargetRequiresUnwindTables, UnstableVirtualFunctionElimination, UnsupportedDwarfVersion,
+    TargetRequiresUnwindTables, UnleashedFeatureHelp, UnstableVirtualFunctionElimination,
+    UnsupportedDwarfVersion,
 };
 use crate::parse::{add_feature_diagnostics, ParseSess};
 use crate::search_paths::{PathKind, SearchPath};
@@ -44,7 +45,6 @@ use rustc_target::spec::{
 use std::cell::{self, RefCell};
 use std::env;
 use std::fmt;
-use std::io::Write;
 use std::ops::{Div, Mul};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
@@ -233,21 +233,19 @@ impl Session {
         if !unleashed_features.is_empty() {
             let mut must_err = false;
             // Create a diagnostic pointing at where things got unleashed.
-            // FIXME(#100717): needs eager translation/lists
-            #[allow(rustc::untranslatable_diagnostic)]
-            #[allow(rustc::diagnostic_outside_of_impl)]
-            let mut diag = self.struct_warn("skipping const checks");
-            for &(span, feature_gate) in unleashed_features.iter() {
-                // FIXME: `span_label` doesn't do anything, so we use "help" as a hack.
-                if let Some(gate) = feature_gate {
-                    diag.span_help(span, &format!("skipping check for `{gate}` feature"));
-                    // The unleash flag must *not* be used to just "hack around" feature gates.
-                    must_err = true;
-                } else {
-                    diag.span_help(span, "skipping check that does not even have a feature gate");
-                }
-            }
-            diag.emit();
+            self.emit_warning(SkippingConstChecks {
+                unleashed_features: unleashed_features
+                    .iter()
+                    .map(|(span, gate)| {
+                        gate.map(|gate| {
+                            must_err = true;
+                            UnleashedFeatureHelp::Named { span: *span, gate }
+                        })
+                        .unwrap_or(UnleashedFeatureHelp::Unnamed { span: *span })
+                    })
+                    .collect(),
+            });
+
             // If we should err, make sure we did.
             if must_err && self.has_errors().is_none() {
                 // We have skipped a feature gate, and not run into other errors... reject.
@@ -288,6 +286,7 @@ impl Session {
     }
 
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_warn<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -296,6 +295,7 @@ impl Session {
         self.diagnostic().struct_span_warn(sp, msg)
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -305,6 +305,7 @@ impl Session {
         self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -314,10 +315,12 @@ impl Session {
         self.diagnostic().struct_span_warn_with_code(sp, msg, code)
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_warn(msg)
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_warn_with_expectation(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -326,6 +329,7 @@ impl Session {
         self.diagnostic().struct_warn_with_expectation(msg, id)
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_allow<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -334,10 +338,12 @@ impl Session {
         self.diagnostic().struct_span_allow(sp, msg)
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_allow(msg)
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_expect(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -346,6 +352,7 @@ impl Session {
         self.diagnostic().struct_expect(msg, id)
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -354,6 +361,7 @@ impl Session {
         self.diagnostic().struct_span_err(sp, msg)
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -364,12 +372,14 @@ impl Session {
     }
     // FIXME: This method should be removed (every error should have an associated error code).
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         self.parse_sess.struct_err(msg)
     }
+    #[track_caller]
     #[rustc_lint_diagnostics]
     pub fn struct_err_with_code(
         &self,
@@ -379,6 +389,7 @@ impl Session {
         self.diagnostic().struct_err_with_code(msg, code)
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_warn_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -387,6 +398,7 @@ impl Session {
         self.diagnostic().struct_warn_with_code(msg, code)
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn struct_span_fatal<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -409,6 +421,7 @@ impl Session {
     }
 
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
         self.diagnostic().span_fatal(sp, msg)
     }
@@ -426,6 +439,7 @@ impl Session {
         self.diagnostic().fatal(msg).raise()
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn span_err_or_warn<S: Into<MultiSpan>>(
         &self,
         is_warning: bool,
@@ -439,6 +453,7 @@ impl Session {
         }
     }
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub fn span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -459,12 +474,14 @@ impl Session {
     pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
         self.diagnostic().err(msg)
     }
+    #[track_caller]
     pub fn create_err<'a>(
         &'a self,
         err: impl IntoDiagnostic<'a>,
     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         self.parse_sess.create_err(err)
     }
+    #[track_caller]
     pub fn create_feature_err<'a>(
         &'a self,
         err: impl IntoDiagnostic<'a>,
@@ -477,33 +494,40 @@ impl Session {
         add_feature_diagnostics(&mut err, &self.parse_sess, feature);
         err
     }
+    #[track_caller]
     pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
         self.parse_sess.emit_err(err)
     }
+    #[track_caller]
     pub fn create_warning<'a>(
         &'a self,
         err: impl IntoDiagnostic<'a, ()>,
     ) -> DiagnosticBuilder<'a, ()> {
         self.parse_sess.create_warning(err)
     }
+    #[track_caller]
     pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
         self.parse_sess.emit_warning(warning)
     }
+    #[track_caller]
     pub fn create_note<'a>(
         &'a self,
         note: impl IntoDiagnostic<'a, Noted>,
     ) -> DiagnosticBuilder<'a, Noted> {
         self.parse_sess.create_note(note)
     }
+    #[track_caller]
     pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
         self.parse_sess.emit_note(note)
     }
+    #[track_caller]
     pub fn create_fatal<'a>(
         &'a self,
         fatal: impl IntoDiagnostic<'a, !>,
     ) -> DiagnosticBuilder<'a, !> {
         self.parse_sess.create_fatal(fatal)
     }
+    #[track_caller]
     pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! {
         self.parse_sess.emit_fatal(fatal)
     }
@@ -543,6 +567,7 @@ impl Session {
     }
     #[allow(rustc::untranslatable_diagnostic)]
     #[allow(rustc::diagnostic_outside_of_impl)]
+    #[track_caller]
     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
         self.diagnostic().span_warn(sp, msg)
     }
@@ -589,6 +614,8 @@ impl Session {
     pub fn note_without_error(&self, msg: impl Into<DiagnosticMessage>) {
         self.diagnostic().note_without_error(msg)
     }
+
+    #[track_caller]
     pub fn span_note_without_error<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -991,11 +1018,8 @@ impl Session {
                 return config::Lto::Fat;
             }
             config::LtoCli::Thin => {
-                return if self.opts.cli_forced_thinlto_off {
-                    config::Lto::Fat
-                } else {
-                    config::Lto::Thin
-                };
+                // The user explicitly asked for ThinLTO
+                return config::Lto::Thin;
             }
         }
 
@@ -1007,7 +1031,7 @@ impl Session {
 
         // If processing command line options determined that we're incompatible
         // with ThinLTO (e.g., `-C lto --emit llvm-ir`) then return that option.
-        if self.opts.cli_forced_thinlto_off {
+        if self.opts.cli_forced_local_thinlto_off {
             return config::Lto::No;
         }
 
@@ -1213,11 +1237,11 @@ fn default_emitter(
     source_map: Lrc<SourceMap>,
     bundle: Option<Lrc<FluentBundle>>,
     fallback_bundle: LazyFallbackBundle,
-    emitter_dest: Option<Box<dyn Write + Send>>,
 ) -> Box<dyn Emitter + sync::Send> {
     let macro_backtrace = sopts.unstable_opts.macro_backtrace;
-    match (sopts.error_format, emitter_dest) {
-        (config::ErrorOutputType::HumanReadable(kind), dst) => {
+    let track_diagnostics = sopts.unstable_opts.track_diagnostics;
+    match sopts.error_format {
+        config::ErrorOutputType::HumanReadable(kind) => {
             let (short, color_config) = kind.unzip();
 
             if let HumanReadableErrorType::AnnotateSnippet(_) = kind {
@@ -1230,33 +1254,21 @@ fn default_emitter(
                 );
                 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
             } else {
-                let emitter = match dst {
-                    None => EmitterWriter::stderr(
-                        color_config,
-                        Some(source_map),
-                        bundle,
-                        fallback_bundle,
-                        short,
-                        sopts.unstable_opts.teach,
-                        sopts.diagnostic_width,
-                        macro_backtrace,
-                    ),
-                    Some(dst) => EmitterWriter::new(
-                        dst,
-                        Some(source_map),
-                        bundle,
-                        fallback_bundle,
-                        short,
-                        false, // no teach messages when writing to a buffer
-                        false, // no colors when writing to a buffer
-                        None,  // no diagnostic width
-                        macro_backtrace,
-                    ),
-                };
+                let emitter = EmitterWriter::stderr(
+                    color_config,
+                    Some(source_map),
+                    bundle,
+                    fallback_bundle,
+                    short,
+                    sopts.unstable_opts.teach,
+                    sopts.diagnostic_width,
+                    macro_backtrace,
+                    track_diagnostics,
+                );
                 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
             }
         }
-        (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new(
+        config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(
             JsonEmitter::stderr(
                 Some(registry),
                 source_map,
@@ -1266,31 +1278,13 @@ fn default_emitter(
                 json_rendered,
                 sopts.diagnostic_width,
                 macro_backtrace,
-            )
-            .ui_testing(sopts.unstable_opts.ui_testing),
-        ),
-        (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new(
-            JsonEmitter::new(
-                dst,
-                Some(registry),
-                source_map,
-                bundle,
-                fallback_bundle,
-                pretty,
-                json_rendered,
-                sopts.diagnostic_width,
-                macro_backtrace,
+                track_diagnostics,
             )
             .ui_testing(sopts.unstable_opts.ui_testing),
         ),
     }
 }
 
-pub enum DiagnosticOutput {
-    Default,
-    Raw(Box<dyn Write + Send>),
-}
-
 // JUSTIFICATION: literally session construction
 #[allow(rustc::bad_opt_access)]
 pub fn build_session(
@@ -1298,7 +1292,6 @@ pub fn build_session(
     local_crate_source_file: Option<PathBuf>,
     bundle: Option<Lrc<rustc_errors::FluentBundle>>,
     registry: rustc_errors::registry::Registry,
-    diagnostics_output: DiagnosticOutput,
     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
     target_override: Option<Target>,
@@ -1314,11 +1307,6 @@ pub fn build_session(
     let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow);
     let can_emit_warnings = !(warnings_allow || cap_lints_allow);
 
-    let write_dest = match diagnostics_output {
-        DiagnosticOutput::Default => None,
-        DiagnosticOutput::Raw(write) => Some(write),
-    };
-
     let sysroot = match &sopts.maybe_sysroot {
         Some(sysroot) => sysroot.clone(),
         None => filesearch::get_or_default_sysroot(),
@@ -1351,8 +1339,7 @@ pub fn build_session(
         rustc_errors::DEFAULT_LOCALE_RESOURCES,
         sopts.unstable_opts.translate_directionality_markers,
     );
-    let emitter =
-        default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle, write_dest);
+    let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle);
 
     let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags(
         emitter,
@@ -1594,11 +1581,18 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler
                 false,
                 None,
                 false,
+                false,
             ))
         }
-        config::ErrorOutputType::Json { pretty, json_rendered } => {
-            Box::new(JsonEmitter::basic(pretty, json_rendered, None, fallback_bundle, None, false))
-        }
+        config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(
+            pretty,
+            json_rendered,
+            None,
+            fallback_bundle,
+            None,
+            false,
+            false,
+        )),
     };
     rustc_errors::Handler::with_emitter(true, None, emitter)
 }
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index 9a4f6f9f9ef..e65b6891e32 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -53,6 +53,17 @@ impl NativeLibKind {
             NativeLibKind::RawDylib | NativeLibKind::Unspecified | NativeLibKind::LinkArg => false,
         }
     }
+
+    pub fn is_statically_included(&self) -> bool {
+        matches!(self, NativeLibKind::Static { .. })
+    }
+
+    pub fn is_dllimport(&self) -> bool {
+        matches!(
+            self,
+            NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified
+        )
+    }
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 91eef647713..322c7104be4 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -558,7 +558,7 @@ impl Span {
         self.data_untracked().is_dummy()
     }
 
-    /// Returns `true` if this span comes from a macro or desugaring.
+    /// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
     #[inline]
     pub fn from_expansion(self) -> bool {
         self.ctxt() != SyntaxContext::root()
@@ -571,6 +571,12 @@ impl Span {
         matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo
     }
 
+    /// Returns `true` if this span comes from MIR inlining.
+    pub fn is_inlined(self) -> bool {
+        let outer_expn = self.ctxt().outer_expn_data();
+        matches!(outer_expn.kind, ExpnKind::Inlined)
+    }
+
     /// Returns `true` if `span` originates in a derive-macro's expansion.
     pub fn in_derive_expansion(self) -> bool {
         matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
@@ -1631,10 +1637,7 @@ impl SourceFile {
     /// number. If the source_file is empty or the position is located before the
     /// first line, `None` is returned.
     pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
-        self.lines(|lines| match lines.partition_point(|x| x <= &pos) {
-            0 => None,
-            i => Some(i - 1),
-        })
+        self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1))
     }
 
     pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 4d94c92d3f2..f9566eeee94 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -853,28 +853,56 @@ impl SourceMap {
     }
 
     /// Returns a new span representing the next character after the end-point of this span.
+    /// Special cases:
+    /// - if span is a dummy one, returns the same span
+    /// - if next_point reached the end of source, return span with lo = hi
+    /// - respect multi-byte characters
     pub fn next_point(&self, sp: Span) -> Span {
         if sp.is_dummy() {
             return sp;
         }
         let start_of_next_point = sp.hi().0;
 
-        let width = self.find_width_of_character_at_span(sp.shrink_to_hi(), true);
-        // If the width is 1, then the next span should point to the same `lo` and `hi`. However,
-        // in the case of a multibyte character, where the width != 1, the next span should
+        let width = self.find_width_of_character_at_span(sp, true);
+        if width == 0 {
+            return Span::new(sp.hi(), sp.hi(), sp.ctxt(), None);
+        }
+        // If the width is 1, then the next span should only contain the next char besides current ending.
+        // However, in the case of a multibyte character, where the width != 1, the next span should
         // span multiple bytes to include the whole character.
         let end_of_next_point =
-            start_of_next_point.checked_add(width - 1).unwrap_or(start_of_next_point);
+            start_of_next_point.checked_add(width).unwrap_or(start_of_next_point);
 
-        let end_of_next_point = BytePos(cmp::max(sp.lo().0 + 1, end_of_next_point));
+        let end_of_next_point = BytePos(cmp::max(start_of_next_point + 1, end_of_next_point));
         Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt(), None)
     }
 
+    /// Returns a new span to check next none-whitespace character or some specified expected character
+    /// If `expect` is none, the first span of non-whitespace character is returned.
+    /// If `expect` presented, the first span of the character `expect` is returned
+    /// Otherwise, the span reached to limit is returned.
+    pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option<usize>) -> Span {
+        let mut sp = span;
+        for _ in 0..limit.unwrap_or(100 as usize) {
+            sp = self.next_point(sp);
+            if let Ok(ref snippet) = self.span_to_snippet(sp) {
+                if expect.map_or(false, |es| snippet == es) {
+                    break;
+                }
+                if expect.is_none() && snippet.chars().any(|c| !c.is_whitespace()) {
+                    break;
+                }
+            }
+        }
+        sp
+    }
+
     /// Finds the width of the character, either before or after the end of provided span,
     /// depending on the `forwards` parameter.
     fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
         let sp = sp.data();
-        if sp.lo == sp.hi {
+
+        if sp.lo == sp.hi && !forwards {
             debug!("find_width_of_character_at_span: early return empty span");
             return 1;
         }
@@ -908,9 +936,9 @@ impl SourceMap {
         let source_len = (local_begin.sf.end_pos - local_begin.sf.start_pos).to_usize();
         debug!("find_width_of_character_at_span: source_len=`{:?}`", source_len);
         // Ensure indexes are also not malformed.
-        if start_index > end_index || end_index > source_len {
+        if start_index > end_index || end_index > source_len - 1 {
             debug!("find_width_of_character_at_span: source indexes are malformed");
-            return 1;
+            return 0;
         }
 
         let src = local_begin.sf.external_src.borrow();
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 3058ec45a64..1fd81018fa0 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -479,3 +479,48 @@ fn path_prefix_remapping_expand_to_absolute() {
         RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") }
     );
 }
+
+#[test]
+fn test_next_point() {
+    let sm = SourceMap::new(FilePathMapping::empty());
+    sm.new_source_file(PathBuf::from("example.rs").into(), "a…b".to_string());
+
+    // Dummy spans don't advance.
+    let span = DUMMY_SP;
+    let span = sm.next_point(span);
+    assert_eq!(span.lo().0, 0);
+    assert_eq!(span.hi().0, 0);
+
+    // Span advance respect multi-byte character
+    let span = Span::with_root_ctxt(BytePos(0), BytePos(1));
+    assert_eq!(sm.span_to_snippet(span), Ok("a".to_string()));
+    let span = sm.next_point(span);
+    assert_eq!(sm.span_to_snippet(span), Ok("…".to_string()));
+    assert_eq!(span.lo().0, 1);
+    assert_eq!(span.hi().0, 4);
+
+    // An empty span pointing just before a multi-byte character should
+    // advance to contain the multi-byte character.
+    let span = Span::with_root_ctxt(BytePos(1), BytePos(1));
+    let span = sm.next_point(span);
+    assert_eq!(span.lo().0, 1);
+    assert_eq!(span.hi().0, 4);
+
+    let span = Span::with_root_ctxt(BytePos(1), BytePos(4));
+    let span = sm.next_point(span);
+    assert_eq!(span.lo().0, 4);
+    assert_eq!(span.hi().0, 5);
+
+    // A non-empty span at the last byte should advance to create an empty
+    // span pointing at the end of the file.
+    let span = Span::with_root_ctxt(BytePos(4), BytePos(5));
+    let span = sm.next_point(span);
+    assert_eq!(span.lo().0, 5);
+    assert_eq!(span.hi().0, 5);
+
+    // Empty span pointing just past the last byte.
+    let span = Span::with_root_ctxt(BytePos(5), BytePos(5));
+    let span = sm.next_point(span);
+    assert_eq!(span.lo().0, 5);
+    assert_eq!(span.hi().0, 5);
+}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index c6711b603b6..cccc4897ecc 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -451,6 +451,7 @@ symbols! {
         call_once,
         caller_location,
         capture_disjoint_fields,
+        cause,
         cdylib,
         ceilf32,
         ceilf64,
@@ -693,6 +694,7 @@ symbols! {
         export_name,
         expr,
         extended_key_value_attributes,
+        extended_varargs_abi_support,
         extern_absolute_paths,
         extern_crate_item_prelude,
         extern_crate_self,
@@ -812,6 +814,7 @@ symbols! {
         impl_lint_pass,
         impl_macros,
         impl_trait_in_bindings,
+        impl_trait_in_fn_trait_return,
         implied_by,
         import,
         import_name_type,
@@ -1900,6 +1903,13 @@ impl fmt::Display for Symbol {
     }
 }
 
+// takes advantage of `str::to_string` specialization
+impl ToString for Symbol {
+    fn to_string(&self) -> String {
+        self.as_str().to_string()
+    }
+}
+
 impl<S: Encoder> Encodable<S> for Symbol {
     default fn encode(&self, s: &mut S) {
         s.emit_str(self.as_str());
diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs
index eb487a03c93..f4d0751f753 100644
--- a/compiler/rustc_symbol_mangling/src/errors.rs
+++ b/compiler/rustc_symbol_mangling/src/errors.rs
@@ -5,7 +5,7 @@ use rustc_macros::Diagnostic;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(symbol_mangling::test_output)]
+#[diag(symbol_mangling_test_output)]
 pub struct TestOutput {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index c8c6fe2bf85..150459ce0f5 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -26,19 +26,19 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) {
         let crate_items = tcx.hir_crate_items(());
 
         for id in crate_items.items() {
-            symbol_names.process_attrs(id.def_id.def_id);
+            symbol_names.process_attrs(id.owner_id.def_id);
         }
 
         for id in crate_items.trait_items() {
-            symbol_names.process_attrs(id.def_id.def_id);
+            symbol_names.process_attrs(id.owner_id.def_id);
         }
 
         for id in crate_items.impl_items() {
-            symbol_names.process_attrs(id.def_id.def_id);
+            symbol_names.process_attrs(id.owner_id.def_id);
         }
 
         for id in crate_items.foreign_items() {
-            symbol_names.process_attrs(id.def_id.def_id);
+            symbol_names.process_attrs(id.owner_id.def_id);
         }
     })
 }
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index aa65a72ab64..6aa031c8378 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -540,7 +540,7 @@ fn encode_ty<'tcx>(
             let mut s = String::new();
             let def_id = adt_def.0.did;
             if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
-                // For for cross-language CFI support, the encoding must be compatible at the FFI
+                // For cross-language CFI support, the encoding must be compatible at the FFI
                 // boundary. For instance:
                 //
                 //     struct type1 {};
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 9fe7da3f29e..9e5f0e4d158 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -47,7 +47,7 @@ pub enum PassMode {
     /// Pass the argument indirectly via a hidden pointer.
     /// The `extra_attrs` value, if any, is for the extra data (vtable or length)
     /// which indicates that it refers to an unsized rvalue.
-    /// `on_stack` defines that the the value should be passed at a fixed
+    /// `on_stack` defines that the value should be passed at a fixed
     /// stack offset in accordance to the ABI rather than passed using a
     /// pointer. This corresponds to the `byval` LLVM argument attribute.
     Indirect { attrs: ArgAttributes, extra_attrs: Option<ArgAttributes>, on_stack: bool },
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index c915124434b..cb2a0c04c6a 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -40,6 +40,28 @@ pub enum Abi {
     RustCold,
 }
 
+impl Abi {
+    pub fn supports_varargs(self) -> bool {
+        // * C and Cdecl obviously support varargs.
+        // * C can be based on SysV64 or Win64, so they must support varargs.
+        // * EfiApi is based on Win64 or C, so it also supports it.
+        //
+        // * Stdcall does not, because it would be impossible for the callee to clean
+        //   up the arguments. (callee doesn't know how many arguments are there)
+        // * Same for Fastcall, Vectorcall and Thiscall.
+        // * System can become Stdcall, so is also a no-no.
+        // * Other calling conventions are related to hardware or the compiler itself.
+        match self {
+            Self::C { .. }
+            | Self::Cdecl { .. }
+            | Self::Win64 { .. }
+            | Self::SysV64 { .. }
+            | Self::EfiApi => true,
+            _ => false,
+        }
+    }
+}
+
 #[derive(Copy, Clone)]
 pub struct AbiData {
     abi: Abi,
@@ -109,175 +131,125 @@ pub enum AbiDisabled {
     Unrecognized,
 }
 
-fn gate_feature_post(
+pub fn is_enabled(
     features: &rustc_feature::Features,
-    feature: Symbol,
     span: Span,
-    explain: &'static str,
+    name: &str,
 ) -> Result<(), AbiDisabled> {
-    if !features.enabled(feature) && !span.allows_unstable(feature) {
-        Err(AbiDisabled::Unstable { feature, explain })
-    } else {
-        Ok(())
+    let s = is_stable(name);
+    if let Err(AbiDisabled::Unstable { feature, .. }) = s {
+        if features.enabled(feature) || span.allows_unstable(feature) {
+            return Ok(());
+        }
     }
+    s
 }
 
-pub fn is_enabled(
-    features: &rustc_feature::Features,
-    span: Span,
-    name: &str,
-) -> Result<(), AbiDisabled> {
+pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
     match name {
         // Stable
         "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
         | "system" => Ok(()),
-        "rust-intrinsic" => {
-            gate_feature_post(features, sym::intrinsics, span, "intrinsics are subject to change")
-        }
-        "platform-intrinsic" => gate_feature_post(
-            features,
-            sym::platform_intrinsics,
-            span,
-            "platform intrinsics are experimental and possibly buggy",
-        ),
-        "vectorcall" => gate_feature_post(
-            features,
-            sym::abi_vectorcall,
-            span,
-            "vectorcall is experimental and subject to change",
-        ),
-        "thiscall" => gate_feature_post(
-            features,
-            sym::abi_thiscall,
-            span,
-            "thiscall is experimental and subject to change",
-        ),
-        "rust-call" => gate_feature_post(
-            features,
-            sym::unboxed_closures,
-            span,
-            "rust-call ABI is subject to change",
-        ),
-        "rust-cold" => gate_feature_post(
-            features,
-            sym::rust_cold_cc,
-            span,
-            "rust-cold is experimental and subject to change",
-        ),
-        "ptx-kernel" => gate_feature_post(
-            features,
-            sym::abi_ptx,
-            span,
-            "PTX ABIs are experimental and subject to change",
-        ),
-        "unadjusted" => gate_feature_post(
-            features,
-            sym::abi_unadjusted,
-            span,
-            "unadjusted ABI is an implementation detail and perma-unstable",
-        ),
-        "msp430-interrupt" => gate_feature_post(
-            features,
-            sym::abi_msp430_interrupt,
-            span,
-            "msp430-interrupt ABI is experimental and subject to change",
-        ),
-        "x86-interrupt" => gate_feature_post(
-            features,
-            sym::abi_x86_interrupt,
-            span,
-            "x86-interrupt ABI is experimental and subject to change",
-        ),
-        "amdgpu-kernel" => gate_feature_post(
-            features,
-            sym::abi_amdgpu_kernel,
-            span,
-            "amdgpu-kernel ABI is experimental and subject to change",
-        ),
-        "avr-interrupt" | "avr-non-blocking-interrupt" => gate_feature_post(
-            features,
-            sym::abi_avr_interrupt,
-            span,
-            "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
-        ),
-        "efiapi" => gate_feature_post(
-            features,
-            sym::abi_efiapi,
-            span,
-            "efiapi ABI is experimental and subject to change",
-        ),
-        "C-cmse-nonsecure-call" => gate_feature_post(
-            features,
-            sym::abi_c_cmse_nonsecure_call,
-            span,
-            "C-cmse-nonsecure-call ABI is experimental and subject to change",
-        ),
-        "C-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "C-unwind ABI is experimental and subject to change",
-        ),
-        "stdcall-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "stdcall-unwind ABI is experimental and subject to change",
-        ),
-        "system-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "system-unwind ABI is experimental and subject to change",
-        ),
-        "thiscall-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "thiscall-unwind ABI is experimental and subject to change",
-        ),
-        "cdecl-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "cdecl-unwind ABI is experimental and subject to change",
-        ),
-        "fastcall-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "fastcall-unwind ABI is experimental and subject to change",
-        ),
-        "vectorcall-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "vectorcall-unwind ABI is experimental and subject to change",
-        ),
-        "aapcs-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "aapcs-unwind ABI is experimental and subject to change",
-        ),
-        "win64-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "win64-unwind ABI is experimental and subject to change",
-        ),
-        "sysv64-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "sysv64-unwind ABI is experimental and subject to change",
-        ),
-        "wasm" => gate_feature_post(
-            features,
-            sym::wasm_abi,
-            span,
-            "wasm ABI is experimental and subject to change",
-        ),
+        "rust-intrinsic" => Err(AbiDisabled::Unstable {
+            feature: sym::intrinsics,
+            explain: "intrinsics are subject to change",
+        }),
+        "platform-intrinsic" => Err(AbiDisabled::Unstable {
+            feature: sym::platform_intrinsics,
+            explain: "platform intrinsics are experimental and possibly buggy",
+        }),
+        "vectorcall" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_vectorcall,
+            explain: "vectorcall is experimental and subject to change",
+        }),
+        "thiscall" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_thiscall,
+            explain: "thiscall is experimental and subject to change",
+        }),
+        "rust-call" => Err(AbiDisabled::Unstable {
+            feature: sym::unboxed_closures,
+            explain: "rust-call ABI is subject to change",
+        }),
+        "rust-cold" => Err(AbiDisabled::Unstable {
+            feature: sym::rust_cold_cc,
+            explain: "rust-cold is experimental and subject to change",
+        }),
+        "ptx-kernel" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_ptx,
+            explain: "PTX ABIs are experimental and subject to change",
+        }),
+        "unadjusted" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_unadjusted,
+            explain: "unadjusted ABI is an implementation detail and perma-unstable",
+        }),
+        "msp430-interrupt" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_msp430_interrupt,
+            explain: "msp430-interrupt ABI is experimental and subject to change",
+        }),
+        "x86-interrupt" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_x86_interrupt,
+            explain: "x86-interrupt ABI is experimental and subject to change",
+        }),
+        "amdgpu-kernel" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_amdgpu_kernel,
+            explain: "amdgpu-kernel ABI is experimental and subject to change",
+        }),
+        "avr-interrupt" | "avr-non-blocking-interrupt" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_avr_interrupt,
+            explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
+        }),
+        "efiapi" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_efiapi,
+            explain: "efiapi ABI is experimental and subject to change",
+        }),
+        "C-cmse-nonsecure-call" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_c_cmse_nonsecure_call,
+            explain: "C-cmse-nonsecure-call ABI is experimental and subject to change",
+        }),
+        "C-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "C-unwind ABI is experimental and subject to change",
+        }),
+        "stdcall-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "stdcall-unwind ABI is experimental and subject to change",
+        }),
+        "system-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "system-unwind ABI is experimental and subject to change",
+        }),
+        "thiscall-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "thiscall-unwind ABI is experimental and subject to change",
+        }),
+        "cdecl-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "cdecl-unwind ABI is experimental and subject to change",
+        }),
+        "fastcall-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "fastcall-unwind ABI is experimental and subject to change",
+        }),
+        "vectorcall-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "vectorcall-unwind ABI is experimental and subject to change",
+        }),
+        "aapcs-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "aapcs-unwind ABI is experimental and subject to change",
+        }),
+        "win64-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "win64-unwind ABI is experimental and subject to change",
+        }),
+        "sysv64-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "sysv64-unwind ABI is experimental and subject to change",
+        }),
+        "wasm" => Err(AbiDisabled::Unstable {
+            feature: sym::wasm_abi,
+            explain: "wasm ABI is experimental and subject to change",
+        }),
         _ => Err(AbiDisabled::Unrecognized),
     }
 }
diff --git a/compiler/rustc_target/src/spec/apple/tests.rs b/compiler/rustc_target/src/spec/apple/tests.rs
new file mode 100644
index 00000000000..d062b36742d
--- /dev/null
+++ b/compiler/rustc_target/src/spec/apple/tests.rs
@@ -0,0 +1,20 @@
+use crate::spec::{
+    aarch64_apple_ios_sim, aarch64_apple_watchos_sim, x86_64_apple_ios, x86_64_apple_tvos,
+    x86_64_apple_watchos_sim,
+};
+
+#[test]
+fn simulator_targets_set_abi() {
+    let all_sim_targets = [
+        x86_64_apple_ios::target(),
+        x86_64_apple_tvos::target(),
+        x86_64_apple_watchos_sim::target(),
+        aarch64_apple_ios_sim::target(),
+        // Note: There is currently no ARM64 tvOS simulator target
+        aarch64_apple_watchos_sim::target(),
+    ];
+
+    for target in all_sim_targets {
+        assert_eq!(target.abi, "sim")
+    }
+}
diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs
index 49e302676a7..148031b1569 100644
--- a/compiler/rustc_target/src/spec/apple_sdk_base.rs
+++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs
@@ -1,6 +1,10 @@
 use crate::spec::{cvs, TargetOptions};
 use std::borrow::Cow;
 
+#[cfg(test)]
+#[path = "apple/tests.rs"]
+mod tests;
+
 use Arch::*;
 #[allow(non_camel_case_types)]
 #[derive(Copy, Clone)]
@@ -11,7 +15,9 @@ pub enum Arch {
     Arm64,
     Arm64_32,
     I386,
+    #[allow(dead_code)] // Some targets don't use this enum...
     X86_64,
+    X86_64_sim,
     X86_64_macabi,
     Arm64_macabi,
     Arm64_sim,
@@ -25,7 +31,7 @@ fn target_arch_name(arch: Arch) -> &'static str {
         Arm64 | Arm64_macabi | Arm64_sim => "arm64",
         Arm64_32 => "arm64_32",
         I386 => "i386",
-        X86_64 | X86_64_macabi => "x86_64",
+        X86_64 | X86_64_sim | X86_64_macabi => "x86_64",
     }
 }
 
@@ -33,7 +39,9 @@ fn target_abi(arch: Arch) -> &'static str {
     match arch {
         Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 => "",
         X86_64_macabi | Arm64_macabi => "macabi",
-        Arm64_sim => "sim",
+        // x86_64-apple-ios is a simulator target, even though it isn't
+        // declared that way in the target like the other ones...
+        Arm64_sim | X86_64_sim => "sim",
     }
 }
 
@@ -45,7 +53,7 @@ fn target_cpu(arch: Arch) -> &'static str {
         Arm64 => "apple-a7",
         Arm64_32 => "apple-s4",
         I386 => "yonah",
-        X86_64 => "core2",
+        X86_64 | X86_64_sim => "core2",
         X86_64_macabi => "core2",
         Arm64_macabi => "apple-a12",
         Arm64_sim => "apple-a12",
@@ -54,7 +62,7 @@ fn target_cpu(arch: Arch) -> &'static str {
 
 fn link_env_remove(arch: Arch) -> Cow<'static, [Cow<'static, str>]> {
     match arch {
-        Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 | Arm64_sim => {
+        Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 | X86_64_sim | Arm64_sim => {
             cvs!["MACOSX_DEPLOYMENT_TARGET"]
         }
         X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"],
@@ -62,11 +70,12 @@ fn link_env_remove(arch: Arch) -> Cow<'static, [Cow<'static, str>]> {
 }
 
 pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
+    let abi = target_abi(arch);
     TargetOptions {
-        abi: target_abi(arch).into(),
+        abi: abi.into(),
         cpu: target_cpu(arch).into(),
         link_env_remove: link_env_remove(arch),
         has_thread_local: false,
-        ..super::apple_base::opts(os, target_arch_name(arch), target_abi(arch))
+        ..super::apple_base::opts(os, target_arch_name(arch), abi)
     }
 }
diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psx.rs b/compiler/rustc_target/src/spec/mipsel_sony_psx.rs
new file mode 100644
index 00000000000..12a66efdd46
--- /dev/null
+++ b/compiler/rustc_target/src/spec/mipsel_sony_psx.rs
@@ -0,0 +1,37 @@
+use crate::spec::{cvs, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "mipsel-sony-psx".into(),
+        pointer_width: 32,
+        data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
+        arch: "mips".into(),
+
+        options: TargetOptions {
+            os: "none".into(),
+            env: "psx".into(),
+            vendor: "sony".into(),
+            linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+            cpu: "mips1".into(),
+            executables: true,
+            linker: Some("rust-lld".into()),
+            relocation_model: RelocModel::Static,
+            exe_suffix: ".exe".into(),
+
+            // PSX doesn't natively support floats.
+            features: "+soft-float".into(),
+
+            // This should be 16 bits, but LLVM incorrectly tries emitting MIPS-II SYNC instructions
+            // for atomic loads and stores. This crashes rustc so we have to disable the Atomic* API
+            // until this is fixed upstream. See https://reviews.llvm.org/D122427#3420144 for more
+            // info.
+            max_atomic_width: Some(0),
+
+            // PSX does not support trap-on-condition instructions.
+            llvm_args: cvs!["-mno-check-zero-division"],
+            llvm_abiname: "o32".into(),
+            panic_strategy: PanicStrategy::Abort,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 8909cf33af9..72b088d663b 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1222,6 +1222,7 @@ supported_targets! {
     ("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf),
 
     ("mipsel-sony-psp", mipsel_sony_psp),
+    ("mipsel-sony-psx", mipsel_sony_psx),
     ("mipsel-unknown-none", mipsel_unknown_none),
     ("thumbv4t-none-eabi", thumbv4t_none_eabi),
     ("armv4t-none-eabi", armv4t_none_eabi),
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
index e6143025d6d..db23f01c233 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
@@ -2,7 +2,7 @@ use super::apple_sdk_base::{opts, Arch};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::X86_64);
+    let base = opts("ios", Arch::X86_64_sim);
     let llvm_target = super::apple_base::ios_sim_llvm_target("x86_64");
 
     Target {
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
index 3d54da0867c..c1fd8e1c8b9 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
@@ -2,7 +2,7 @@ use super::apple_sdk_base::{opts, Arch};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("tvos", Arch::X86_64);
+    let base = opts("tvos", Arch::X86_64_sim);
     Target {
         llvm_target: "x86_64-apple-tvos".into(),
         pointer_width: 64,
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs
index e499b1985e7..550566b2aa7 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs
@@ -2,7 +2,7 @@ use super::apple_sdk_base::{opts, Arch};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("watchos", Arch::X86_64);
+    let base = opts("watchos", Arch::X86_64_sim);
 
     let arch = "x86_64";
     let llvm_target = super::apple_base::watchos_sim_llvm_target(arch);
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 61793468594..23c3715860e 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -5,7 +5,7 @@ use rustc_session::Limit;
 use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
-#[diag(trait_selection::dump_vtable_entries)]
+#[diag(trait_selection_dump_vtable_entries)]
 pub struct DumpVTableEntries<'a> {
     #[primary_span]
     pub span: Span,
@@ -14,7 +14,7 @@ pub struct DumpVTableEntries<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(trait_selection::unable_to_construct_constant_value)]
+#[diag(trait_selection_unable_to_construct_constant_value)]
 pub struct UnableToConstructConstantValue<'a> {
     #[primary_span]
     pub span: Span,
@@ -23,7 +23,7 @@ pub struct UnableToConstructConstantValue<'a> {
 
 #[derive(Diagnostic)]
 #[help]
-#[diag(trait_selection::auto_deref_reached_recursion_limit, code = "E0055")]
+#[diag(trait_selection_auto_deref_reached_recursion_limit, code = "E0055")]
 pub struct AutoDerefReachedRecursionLimit<'a> {
     #[primary_span]
     #[label]
@@ -34,7 +34,7 @@ pub struct AutoDerefReachedRecursionLimit<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(trait_selection::empty_on_clause_in_rustc_on_unimplemented, code = "E0232")]
+#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = "E0232")]
 pub struct EmptyOnClauseInOnUnimplemented {
     #[primary_span]
     #[label]
@@ -42,7 +42,7 @@ pub struct EmptyOnClauseInOnUnimplemented {
 }
 
 #[derive(Diagnostic)]
-#[diag(trait_selection::invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")]
+#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")]
 pub struct InvalidOnClauseInOnUnimplemented {
     #[primary_span]
     #[label]
@@ -50,7 +50,7 @@ pub struct InvalidOnClauseInOnUnimplemented {
 }
 
 #[derive(Diagnostic)]
-#[diag(trait_selection::no_value_in_rustc_on_unimplemented, code = "E0232")]
+#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = "E0232")]
 #[note]
 pub struct NoValueInOnUnimplemented {
     #[primary_span]
@@ -67,11 +67,12 @@ pub struct NegativePositiveConflict<'a> {
 }
 
 impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
+    #[track_caller]
     fn into_diagnostic(
         self,
         handler: &Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::trait_selection::negative_positive_conflict);
+        let mut diag = handler.struct_err(fluent::trait_selection_negative_positive_conflict);
         diag.set_arg("trait_desc", self.trait_desc);
         diag.set_arg(
             "self_desc",
@@ -81,19 +82,19 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
         diag.code(rustc_errors::error_code!(E0751));
         match self.negative_impl_span {
             Ok(span) => {
-                diag.span_label(span, fluent::trait_selection::negative_implementation_here);
+                diag.span_label(span, fluent::negative_implementation_here);
             }
             Err(cname) => {
-                diag.note(fluent::trait_selection::negative_implementation_in_crate);
+                diag.note(fluent::negative_implementation_in_crate);
                 diag.set_arg("negative_impl_cname", cname.to_string());
             }
         }
         match self.positive_impl_span {
             Ok(span) => {
-                diag.span_label(span, fluent::trait_selection::positive_implementation_here);
+                diag.span_label(span, fluent::positive_implementation_here);
             }
             Err(cname) => {
-                diag.note(fluent::trait_selection::positive_implementation_in_crate);
+                diag.note(fluent::positive_implementation_in_crate);
                 diag.set_arg("positive_impl_cname", cname.to_string());
             }
         }
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 1b58c9b864e..96ac4e9c129 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -1,5 +1,5 @@
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::{self, TraitEngine, TraitEngineExt};
+use crate::traits::{self, ObligationCtxt};
 
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
@@ -69,7 +69,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         let ty = self.resolve_vars_if_possible(ty);
 
         if !(param_env, ty).needs_infer() {
-            return ty.is_copy_modulo_regions(self.tcx.at(span), param_env);
+            return ty.is_copy_modulo_regions(self.tcx, param_env);
         }
 
         let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None);
@@ -142,7 +142,7 @@ pub trait InferCtxtBuilderExt<'tcx> {
     fn enter_canonical_trait_query<K, R>(
         &mut self,
         canonical_key: &Canonical<'tcx, K>,
-        operation: impl FnOnce(&InferCtxt<'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
+        operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
     where
         K: TypeFoldable<'tcx>,
@@ -170,17 +170,17 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
     fn enter_canonical_trait_query<K, R>(
         &mut self,
         canonical_key: &Canonical<'tcx, K>,
-        operation: impl FnOnce(&InferCtxt<'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
+        operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
     where
         K: TypeFoldable<'tcx>,
         R: Debug + TypeFoldable<'tcx>,
         Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
     {
-        let (ref infcx, key, canonical_inference_vars) =
+        let (infcx, key, canonical_inference_vars) =
             self.build_with_canonical(DUMMY_SP, canonical_key);
-        let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-        let value = operation(infcx, &mut *fulfill_cx, key)?;
-        infcx.make_canonicalized_query_response(canonical_inference_vars, value, &mut *fulfill_cx)
+        let ocx = ObligationCtxt::new(&infcx);
+        let value = operation(&ocx, key)?;
+        ocx.make_canonicalized_query_response(canonical_inference_vars, value)
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 7fc5c2ed0ea..8aab75490a8 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -60,23 +60,17 @@ pub fn add_placeholder_note(err: &mut Diagnostic) {
     );
 }
 
-/// If there are types that satisfy both impls, invokes `on_overlap`
+/// If there are types that satisfy both impls, returns `Some`
 /// with a suitably-freshened `ImplHeader` with those types
-/// substituted. Otherwise, invokes `no_overlap`.
-#[instrument(skip(tcx, skip_leak_check, on_overlap, no_overlap), level = "debug")]
-pub fn overlapping_impls<F1, F2, R>(
+/// substituted. Otherwise, returns `None`.
+#[instrument(skip(tcx, skip_leak_check), level = "debug")]
+pub fn overlapping_impls(
     tcx: TyCtxt<'_>,
     impl1_def_id: DefId,
     impl2_def_id: DefId,
     skip_leak_check: SkipLeakCheck,
     overlap_mode: OverlapMode,
-    on_overlap: F1,
-    no_overlap: F2,
-) -> R
-where
-    F1: FnOnce(OverlapResult<'_>) -> R,
-    F2: FnOnce() -> R,
-{
+) -> Option<OverlapResult<'_>> {
     // Before doing expensive operations like entering an inference context, do
     // a quick check via fast_reject to tell if the impl headers could possibly
     // unify.
@@ -97,7 +91,7 @@ where
     if !may_overlap {
         // Some types involved are definitely different, so the impls couldn't possibly overlap.
         debug!("overlapping_impls: fast_reject early-exit");
-        return no_overlap();
+        return None;
     }
 
     let infcx = tcx.infer_ctxt().build();
@@ -105,7 +99,7 @@ where
     let overlaps =
         overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
     if !overlaps {
-        return no_overlap();
+        return None;
     }
 
     // In the case where we detect an error, run the check again, but
@@ -114,7 +108,7 @@ where
     let infcx = tcx.infer_ctxt().build();
     let selcx = &mut SelectionContext::intercrate(&infcx);
     selcx.enable_tracking_intercrate_ambiguity_causes();
-    on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
+    Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
 }
 
 fn with_fresh_ty_vars<'cx, 'tcx>(
@@ -193,7 +187,7 @@ fn overlap_within_probe<'cx, 'tcx>(
         }
     }
 
-    // We disable the leak when when creating the `snapshot` by using
+    // We disable the leak when creating the `snapshot` by using
     // `infcx.probe_maybe_disable_leak_check`.
     if infcx.leak_check(true, snapshot).is_err() {
         debug!("overlap: leak check failed");
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 8ea3d0fc917..1de85e2f288 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -9,14 +9,12 @@
 //! `thir_abstract_const` which can then be checked for structural equality with other
 //! generic constants mentioned in the `caller_bounds` of the current environment.
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir::def::DefKind;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::abstract_const::{
     walk_abstract_const, AbstractConst, FailureKind, Node, NotConstEvaluatable,
 };
 use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
-use rustc_session::lint;
 use rustc_span::Span;
 
 use std::iter;
@@ -101,7 +99,7 @@ impl<'tcx> ConstUnifyCtxt<'tcx> {
                         a_uv == b_uv
                     }
                     // FIXME(generic_const_exprs): We may want to either actually try
-                    // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
+                    // to evaluate `a_ct` and `b_ct` if they are fully concrete or something like
                     // this, for now we just return false here.
                     _ => false,
                 }
@@ -161,11 +159,20 @@ pub fn try_unify_abstract_consts<'tcx>(
 #[instrument(skip(infcx), level = "debug")]
 pub fn is_const_evaluatable<'tcx>(
     infcx: &InferCtxt<'tcx>,
-    uv: ty::UnevaluatedConst<'tcx>,
+    ct: ty::Const<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     span: Span,
 ) -> Result<(), NotConstEvaluatable> {
     let tcx = infcx.tcx;
+    let uv = match ct.kind() {
+        ty::ConstKind::Unevaluated(uv) => uv,
+        ty::ConstKind::Param(_)
+        | ty::ConstKind::Bound(_, _)
+        | ty::ConstKind::Placeholder(_)
+        | ty::ConstKind::Value(_)
+        | ty::ConstKind::Error(_) => return Ok(()),
+        ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer),
+    };
 
     if tcx.features().generic_const_exprs {
         if let Some(ct) = AbstractConst::new(tcx, uv)? {
@@ -185,12 +192,12 @@ pub fn is_const_evaluatable<'tcx>(
         }
         let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
         match concrete {
-            Err(ErrorHandled::TooGeneric) => {
-                Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
-                    span,
-                    format!("Missing value for constant, but no error reported?"),
-                )))
-            }
+            Err(ErrorHandled::TooGeneric) => Err(NotConstEvaluatable::Error(
+                infcx
+                    .tcx
+                    .sess
+                    .delay_span_bug(span, "Missing value for constant, but no error reported?"),
+            )),
             Err(ErrorHandled::Linted) => {
                 let reported = infcx
                     .tcx
@@ -253,25 +260,7 @@ pub fn is_const_evaluatable<'tcx>(
                 Err(NotConstEvaluatable::Error(reported))
             }
             Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
-            Ok(_) => {
-                if uv.substs.has_non_region_param() {
-                    assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
-                    let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
-
-                    if mir_body.is_polymorphic {
-                        let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
-                        tcx.struct_span_lint_hir(
-                            lint::builtin::CONST_EVALUATABLE_UNCHECKED,
-                            tcx.hir().local_def_id_to_hir_id(local_def_id),
-                            span,
-                            "cannot use constants which depend on generic parameters in types",
-                            |err| err
-                        )
-                    }
-                }
-
-                Ok(())
-            },
+            Ok(_) => Ok(()),
         }
     }
 }
@@ -285,7 +274,7 @@ fn satisfied_from_param_env<'tcx>(
     for pred in param_env.caller_bounds() {
         match pred.kind().skip_binder() {
             ty::PredicateKind::ConstEvaluatable(uv) => {
-                if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
+                if let Some(b_ct) = AbstractConst::from_const(tcx, uv)? {
                     let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
 
                     // Try to unify with each subtree in the AbstractConst to allow for
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index e0c8deec91a..21516c93efb 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -1,14 +1,21 @@
 use std::cell::RefCell;
+use std::fmt::Debug;
 
 use super::TraitEngine;
 use super::{ChalkFulfillmentContext, FulfillmentContext};
 use crate::infer::InferCtxtExt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_infer::infer::at::ToTrace;
+use rustc_infer::infer::canonical::{
+    Canonical, CanonicalVarValues, CanonicalizedQueryResponse, QueryResponse,
+};
 use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_infer::traits::query::Fallible;
 use rustc_infer::traits::{
     FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
 };
+use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::TypeFoldable;
@@ -105,12 +112,12 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
         self.register_infer_ok_obligations(infer_ok)
     }
 
-    pub fn equate_types(
+    pub fn eq<T: ToTrace<'tcx>>(
         &self,
         cause: &ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        expected: Ty<'tcx>,
-        actual: Ty<'tcx>,
+        expected: T,
+        actual: T,
     ) -> Result<(), TypeError<'tcx>> {
         match self.infcx.at(cause, param_env).eq(expected, actual) {
             Ok(InferOk { obligations, value: () }) => {
@@ -121,6 +128,22 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
         }
     }
 
+    pub fn sup<T: ToTrace<'tcx>>(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        expected: T,
+        actual: T,
+    ) -> Result<(), TypeError<'tcx>> {
+        match self.infcx.at(cause, param_env).sup(expected, actual) {
+            Ok(InferOk { obligations, value: () }) => {
+                self.register_obligations(obligations);
+                Ok(())
+            }
+            Err(e) => Err(e),
+        }
+    }
+
     pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> {
         self.engine.borrow_mut().select_all_or_error(self.infcx)
     }
@@ -154,4 +177,20 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
         }
         implied_bounds
     }
+
+    pub fn make_canonicalized_query_response<T>(
+        &self,
+        inference_vars: CanonicalVarValues<'tcx>,
+        answer: T,
+    ) -> Fallible<CanonicalizedQueryResponse<'tcx, T>>
+    where
+        T: Debug + TypeFoldable<'tcx>,
+        Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
+    {
+        self.infcx.make_canonicalized_query_response(
+            inference_vars,
+            answer,
+            &mut **self.engine.borrow_mut(),
+        )
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 4e8baa2dfab..dacce5cd2f6 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2,10 +2,10 @@ pub mod on_unimplemented;
 pub mod suggestions;
 
 use super::{
-    EvaluationResult, FulfillmentContext, FulfillmentError, FulfillmentErrorCode,
-    MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
-    OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow,
-    PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
+    FulfillmentContext, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
+    Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective,
+    OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation,
+    SelectionContext, SelectionError, TraitNotObjectSafe,
 };
 
 use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
@@ -764,6 +764,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty);
                         }
 
+                        let mut unsatisfied_const = false;
                         if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
                             let non_const_predicate = trait_ref.without_const();
                             let non_const_obligation = Obligation {
@@ -773,6 +774,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 recursion_depth: obligation.recursion_depth,
                             };
                             if self.predicate_may_hold(&non_const_obligation) {
+                                unsatisfied_const = true;
                                 err.span_note(
                                     span,
                                     &format!(
@@ -924,7 +926,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 }
                             }
                         } else if !trait_ref.has_non_region_infer()
-                            && self.predicate_can_apply(obligation.param_env, trait_ref)
+                            && self.predicate_can_apply(obligation.param_env, trait_predicate)
                         {
                             // If a where-clause may be useful, remind the
                             // user that they can add it.
@@ -939,7 +941,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 None,
                                 obligation.cause.body_id,
                             );
-                        } else if !suggested {
+                        } else if !suggested && !unsatisfied_const {
                             // Can't show anything else useful, try to find similar impls.
                             let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
                             if !self.report_similar_impl_candidates(
@@ -972,7 +974,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 // useful for less general traits.
                                 if peeled
                                     && !self.tcx.trait_is_auto(def_id)
-                                    && !self.tcx.lang_items().items().contains(&Some(def_id))
+                                    && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
                                 {
                                     let trait_ref = trait_pred.to_poly_trait_ref();
                                     let impl_candidates =
@@ -1304,7 +1306,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
 
                 match obligation.predicate.kind().skip_binder() {
-                    ty::PredicateKind::ConstEvaluatable(uv) => {
+                    ty::PredicateKind::ConstEvaluatable(ct) => {
+                        let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
+                            bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
+                        };
                         let mut err =
                             self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
                         let const_span = self.tcx.def_span(uv.def.did);
@@ -1433,7 +1438,7 @@ trait InferCtxtPrivExt<'tcx> {
     fn predicate_can_apply(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        pred: ty::PolyTraitRef<'tcx>,
+        pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool;
 
     fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>);
@@ -1893,7 +1898,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         let def_id = trait_ref.def_id();
         if impl_candidates.is_empty() {
             if self.tcx.trait_is_auto(def_id)
-                || self.tcx.lang_items().items().contains(&Some(def_id))
+                || self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
                 || self.tcx.get_diagnostic_name(def_id).is_some()
             {
                 // Mentioning implementers of `Copy`, `Debug` and friends is not useful.
@@ -2368,7 +2373,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 if predicate.references_error() || self.is_tainted_by_errors() {
                     return;
                 }
-                let subst = data.substs.iter().find(|g| g.has_non_region_infer());
+                let subst = data.walk().find(|g| g.is_non_region_infer());
                 if let Some(subst) = subst {
                     let err = self.emit_inference_failure_err(
                         body_id,
@@ -2508,7 +2513,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     fn predicate_can_apply(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        pred: ty::PolyTraitRef<'tcx>,
+        pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
         struct ParamToVarFolder<'a, 'tcx> {
             infcx: &'a InferCtxt<'tcx>,
@@ -2552,7 +2557,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             let obligation = Obligation::new(
                 ObligationCause::dummy(),
                 param_env,
-                cleaned_pred.without_const().to_predicate(selcx.tcx()),
+                cleaned_pred.to_predicate(selcx.tcx()),
             );
 
             self.predicate_may_hold(&obligation)
@@ -2796,3 +2801,8 @@ impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor {
         }
     }
 }
+
+pub enum DefIdOrName {
+    DefId(DefId),
+    Name(&'static str),
+}
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 0f20e02d6ec..5eef54c6330 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
@@ -164,6 +164,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
         }
 
+        if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
+            flags.push((sym::cause, Some("MainFunctionType".to_string())));
+        }
+
         // Add all types without trimmed paths.
         ty::print::with_no_trimmed_paths!({
             let generics = self.tcx.generics_of(def_id);
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 fda6a2236b1..d7606d88803 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1,5 +1,5 @@
 use super::{
-    EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
+    DefIdOrName, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
     SelectionContext,
 };
 
@@ -7,6 +7,7 @@ use crate::autoderef::Autoderef;
 use crate::infer::InferCtxt;
 use crate::traits::normalize_to;
 
+use hir::def::CtorOf;
 use hir::HirId;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -22,6 +23,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::hir::map;
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
@@ -29,7 +31,7 @@ use rustc_middle::ty::{
     ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
-use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use std::fmt;
@@ -812,74 +814,136 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
-        // Skipping binder here, remapping below
-        let self_ty = trait_pred.self_ty().skip_binder();
-
-        let (def_id, output_ty, callable) = match *self_ty.kind() {
-            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
-            ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"),
-            _ => return false,
-        };
-        let msg = format!("use parentheses to call the {}", callable);
+        if let ty::PredicateKind::Trait(trait_pred) = obligation.predicate.kind().skip_binder()
+            && Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait()
+        {
+            // Don't suggest calling to turn an unsized type into a sized type
+            return false;
+        }
 
-        // "We should really create a single list of bound vars from the combined vars
-        // from the predicate and function, but instead we just liberate the function bound vars"
-        let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty);
+        // This is duplicated from `extract_callable_info` in typeck, which
+        // relies on autoderef, so we can't use it here.
+        let found = trait_pred.self_ty().skip_binder().peel_refs();
+        let Some((def_id_or_name, output, inputs)) = (match *found.kind()
+        {
+            ty::FnPtr(fn_sig) => {
+                Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs()))
+            }
+            ty::FnDef(def_id, _) => {
+                let fn_sig = found.fn_sig(self.tcx);
+                Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
+            }
+            ty::Closure(def_id, substs) => {
+                let fn_sig = substs.as_closure().sig();
+                Some((
+                    DefIdOrName::DefId(def_id),
+                    fn_sig.output(),
+                    fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
+                ))
+            }
+            ty::Opaque(def_id, substs) => {
+                self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
+                    if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+                    && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+                    // args tuple will always be substs[1]
+                    && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+                    {
+                        Some((
+                            DefIdOrName::DefId(def_id),
+                            pred.kind().rebind(proj.term.ty().unwrap()),
+                            pred.kind().rebind(args.as_slice()),
+                        ))
+                    } else {
+                        None
+                    }
+                })
+            }
+            ty::Dynamic(data, _, ty::Dyn) => {
+                data.iter().find_map(|pred| {
+                    if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
+                    && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
+                    // for existential projection, substs are shifted over by 1
+                    && let ty::Tuple(args) = proj.substs.type_at(0).kind()
+                    {
+                        Some((
+                            DefIdOrName::Name("trait object"),
+                            pred.rebind(proj.term.ty().unwrap()),
+                            pred.rebind(args.as_slice()),
+                        ))
+                    } else {
+                        None
+                    }
+                })
+            }
+            ty::Param(_) => {
+                obligation.param_env.caller_bounds().iter().find_map(|pred| {
+                    if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+                    && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+                    && proj.projection_ty.self_ty() == found
+                    // args tuple will always be substs[1]
+                    && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+                    {
+                        Some((
+                            DefIdOrName::Name("type parameter"),
+                            pred.kind().rebind(proj.term.ty().unwrap()),
+                            pred.kind().rebind(args.as_slice()),
+                        ))
+                    } else {
+                        None
+                    }
+                })
+            }
+            _ => None,
+        }) else { return false; };
+        let output = self.replace_bound_vars_with_fresh_vars(
+            obligation.cause.span,
+            LateBoundRegionConversionTime::FnCall,
+            output,
+        );
+        let inputs = inputs.skip_binder().iter().map(|ty| {
+            self.replace_bound_vars_with_fresh_vars(
+                obligation.cause.span,
+                LateBoundRegionConversionTime::FnCall,
+                inputs.rebind(*ty),
+            )
+        });
 
         // Remapping bound vars here
-        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
+        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));
 
         let new_obligation =
             self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
-
-        match self.evaluate_obligation(&new_obligation) {
-            Ok(
-                EvaluationResult::EvaluatedToOk
-                | EvaluationResult::EvaluatedToOkModuloRegions
-                | EvaluationResult::EvaluatedToOkModuloOpaqueTypes
-                | EvaluationResult::EvaluatedToAmbig,
-            ) => {}
-            _ => return false,
+        if !self.predicate_must_hold_modulo_regions(&new_obligation) {
+            return false;
         }
-        let hir = self.tcx.hir();
+
         // Get the name of the callable and the arguments to be used in the suggestion.
-        let (snippet, sugg) = match hir.get_if_local(def_id) {
-            Some(hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure(hir::Closure { fn_decl, fn_decl_span, .. }),
-                ..
-            })) => {
-                err.span_label(*fn_decl_span, "consider calling this closure");
-                let Some(name) = self.get_closure_name(def_id, err, &msg) else {
-                    return false;
-                };
-                let args = fn_decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
-                let sugg = format!("({})", args);
-                (format!("{}{}", name, sugg), sugg)
-            }
-            Some(hir::Node::Item(hir::Item {
-                ident,
-                kind: hir::ItemKind::Fn(.., body_id),
-                ..
-            })) => {
-                err.span_label(ident.span, "consider calling this function");
-                let body = hir.body(*body_id);
-                let args = body
-                    .params
-                    .iter()
-                    .map(|arg| match &arg.pat.kind {
-                        hir::PatKind::Binding(_, _, ident, None)
-                        // FIXME: provide a better suggestion when encountering `SelfLower`, it
-                        // should suggest a method call.
-                        if ident.name != kw::SelfLower => ident.to_string(),
-                        _ => "_".to_string(),
-                    })
-                    .collect::<Vec<_>>()
-                    .join(", ");
-                let sugg = format!("({})", args);
-                (format!("{}{}", ident, sugg), sugg)
-            }
-            _ => return false,
+        let hir = self.tcx.hir();
+
+        let msg = match def_id_or_name {
+            DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
+                DefKind::Ctor(CtorOf::Struct, _) => {
+                    "use parentheses to construct this tuple struct".to_string()
+                }
+                DefKind::Ctor(CtorOf::Variant, _) => {
+                    "use parentheses to construct this tuple variant".to_string()
+                }
+                kind => format!("use parentheses to call this {}", kind.descr(def_id)),
+            },
+            DefIdOrName::Name(name) => format!("use parentheses to call this {name}"),
         };
+
+        let args = inputs
+            .map(|ty| {
+                if ty.is_suggestable(self.tcx, false) {
+                    format!("/* {ty} */")
+                } else {
+                    "/* value */".to_string()
+                }
+            })
+            .collect::<Vec<_>>()
+            .join(", ");
+
         if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. })
             && obligation.cause.span.can_be_used_for_suggestions()
         {
@@ -890,11 +954,36 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             err.span_suggestion_verbose(
                 obligation.cause.span.shrink_to_hi(),
                 &msg,
-                sugg,
+                format!("({args})"),
                 Applicability::HasPlaceholders,
             );
-        } else {
-            err.help(&format!("{}: `{}`", msg, snippet));
+        } else if let DefIdOrName::DefId(def_id) = def_id_or_name {
+            let name = match hir.get_if_local(def_id) {
+                Some(hir::Node::Expr(hir::Expr {
+                    kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),
+                    ..
+                })) => {
+                    err.span_label(*fn_decl_span, "consider calling this closure");
+                    let Some(name) = self.get_closure_name(def_id, err, &msg) else {
+                        return false;
+                    };
+                    name.to_string()
+                }
+                Some(hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(..), .. })) => {
+                    err.span_label(ident.span, "consider calling this function");
+                    ident.to_string()
+                }
+                Some(hir::Node::Ctor(..)) => {
+                    let name = self.tcx.def_path_str(def_id);
+                    err.span_label(
+                        self.tcx.def_span(def_id),
+                        format!("consider calling the constructor for `{}`", name),
+                    );
+                    name
+                }
+                _ => return false,
+            };
+            err.help(&format!("{msg}: `{name}({args})`"));
         }
         true
     }
@@ -930,7 +1019,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         let mut never_suggest_borrow: Vec<_> =
             [LangItem::Copy, LangItem::Clone, LangItem::Unpin, LangItem::Sized]
                 .iter()
-                .filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok())
+                .filter_map(|lang_item| self.tcx.lang_items().get(*lang_item))
                 .collect();
 
         if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) {
@@ -2937,19 +3026,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             ObligationCauseCode::BinOp { rhs_span: Some(span), is_lit, .. } if *is_lit => span,
             _ => return,
         };
-        match (
-            trait_ref.skip_binder().self_ty().kind(),
-            trait_ref.skip_binder().substs.type_at(1).kind(),
-        ) {
-            (ty::Float(_), ty::Infer(InferTy::IntVar(_))) => {
-                err.span_suggestion_verbose(
-                    rhs_span.shrink_to_hi(),
-                    "consider using a floating-point literal by writing it with `.0`",
-                    ".0",
-                    Applicability::MaybeIncorrect,
-                );
-            }
-            _ => {}
+        if let ty::Float(_) = trait_ref.skip_binder().self_ty().kind()
+            && let ty::Infer(InferTy::IntVar(_)) = trait_ref.skip_binder().substs.type_at(1).kind()
+        {
+            err.span_suggestion_verbose(
+                rhs_span.shrink_to_hi(),
+                "consider using a floating-point literal by writing it with `.0`",
+                ".0",
+                Applicability::MaybeIncorrect,
+            );
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 6eb02395685..a417e1440b9 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -355,7 +355,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 }
 
                 ty::PredicateKind::RegionOutlives(data) => {
-                    if infcx.considering_regions || data.has_placeholders() {
+                    if infcx.considering_regions {
                         infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
                     }
 
@@ -476,9 +476,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         Err(NotConstEvaluatable::MentionsInfer) => {
                             pending_obligation.stalled_on.clear();
                             pending_obligation.stalled_on.extend(
-                                uv.substs
-                                    .iter()
-                                    .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
+                                uv.walk().filter_map(TyOrConstInferVar::maybe_from_generic_arg),
                             );
                             ProcessResult::Unchanged
                         }
@@ -492,19 +490,20 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 }
 
                 ty::PredicateKind::ConstEquate(c1, c2) => {
+                    assert!(
+                        self.selcx.tcx().features().generic_const_exprs,
+                        "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
+                    );
                     debug!(?c1, ?c2, "equating consts");
-                    let tcx = self.selcx.tcx();
-                    if tcx.features().generic_const_exprs {
-                        // FIXME: we probably should only try to unify abstract constants
-                        // if the constants depend on generic parameters.
-                        //
-                        // Let's just see where this breaks :shrug:
-                        if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
-                            (c1.kind(), c2.kind())
-                        {
-                            if infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
-                                return ProcessResult::Changed(vec![]);
-                            }
+                    // FIXME: we probably should only try to unify abstract constants
+                    // if the constants depend on generic parameters.
+                    //
+                    // Let's just see where this breaks :shrug:
+                    if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+                        (c1.kind(), c2.kind())
+                    {
+                        if infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
+                            return ProcessResult::Changed(vec![]);
                         }
                     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 274a366873c..9ee6e0a2bf3 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -390,6 +390,7 @@ pub fn normalize_param_env_or_error<'tcx>(
 }
 
 /// Normalize a type and process all resulting obligations, returning any errors
+#[instrument(skip_all)]
 pub fn fully_normalize<'tcx, T>(
     infcx: &InferCtxt<'tcx>,
     cause: ObligationCause<'tcx>,
@@ -399,28 +400,18 @@ pub fn fully_normalize<'tcx, T>(
 where
     T: TypeFoldable<'tcx>,
 {
-    debug!("fully_normalize_with_fulfillcx(value={:?})", value);
-    let selcx = &mut SelectionContext::new(infcx);
-    let Normalized { value: normalized_value, obligations } =
-        project::normalize(selcx, param_env, cause, value);
-    debug!(
-        "fully_normalize: normalized_value={:?} obligations={:?}",
-        normalized_value, obligations
-    );
-
-    let mut fulfill_cx = FulfillmentContext::new();
-    for obligation in obligations {
-        fulfill_cx.register_predicate_obligation(infcx, obligation);
-    }
-
-    debug!("fully_normalize: select_all_or_error start");
-    let errors = fulfill_cx.select_all_or_error(infcx);
+    let ocx = ObligationCtxt::new(infcx);
+    debug!(?value);
+    let normalized_value = ocx.normalize(cause, param_env, value);
+    debug!(?normalized_value);
+    debug!("select_all_or_error start");
+    let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
         return Err(errors);
     }
-    debug!("fully_normalize: select_all_or_error complete");
+    debug!("select_all_or_error complete");
     let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
-    debug!("fully_normalize: resolved_value={:?}", resolved_value);
+    debug!(?resolved_value);
     Ok(resolved_value)
 }
 
@@ -764,12 +755,9 @@ fn dump_vtable_entries<'tcx>(
     });
 }
 
-fn own_existential_vtable_entries<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_ref: ty::PolyExistentialTraitRef<'tcx>,
-) -> &'tcx [DefId] {
+fn own_existential_vtable_entries<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> &'tcx [DefId] {
     let trait_methods = tcx
-        .associated_items(trait_ref.def_id())
+        .associated_items(trait_def_id)
         .in_definition_order()
         .filter(|item| item.kind == ty::AssocKind::Fn);
     // Now list each method's DefId (for within its trait).
@@ -778,7 +766,7 @@ fn own_existential_vtable_entries<'tcx>(
         let def_id = trait_method.def_id;
 
         // Some methods cannot be called on an object; skip those.
-        if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
+        if !is_vtable_safe_method(tcx, trait_def_id, &trait_method) {
             debug!("own_existential_vtable_entry: not vtable safe");
             return None;
         }
@@ -810,7 +798,7 @@ fn vtable_entries<'tcx>(
 
                 // Lookup the shape of vtable for the trait.
                 let own_existential_entries =
-                    tcx.own_existential_vtable_entries(existential_trait_ref);
+                    tcx.own_existential_vtable_entries(existential_trait_ref.def_id());
 
                 let own_entries = own_existential_entries.iter().copied().map(|def_id| {
                     debug!("vtable_entries: trait_method={:?}", def_id);
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 545524f63a7..0bb25a74dc8 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -837,24 +837,14 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
             }
         }
 
-        fn visit_ty_unevaluated(
-            &mut self,
-            uv: ty::UnevaluatedConst<'tcx>,
-        ) -> ControlFlow<Self::BreakTy> {
+        fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             // Constants can only influence object safety if they reference `Self`.
             // This is only possible for unevaluated constants, so we walk these here.
             //
-            // If `AbstractConst::new` returned an error we already failed compilation
+            // If `AbstractConst::from_const` returned an error we already failed compilation
             // so we don't have to emit an additional error here.
-            //
-            // We currently recurse into abstract consts here but do not recurse in
-            // `is_const_evaluatable`. This means that the object safety check is more
-            // liberal than the const eval check.
-            //
-            // This shouldn't really matter though as we can't really use any
-            // constants which are not considered const evaluatable.
             use rustc_middle::ty::abstract_const::Node;
-            if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv) {
+            if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) {
                 walk_abstract_const(self.tcx, ct, |node| match node.root(self.tcx) {
                     Node::Leaf(leaf) => self.visit_const(leaf),
                     Node::Cast(_, _, ty) => self.visit_ty(ty),
@@ -863,7 +853,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
                     }
                 })
             } else {
-                ControlFlow::CONTINUE
+                ct.super_visit_with(self)
             }
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index cd1e9a97731..c8276854016 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -264,7 +264,7 @@ fn project_and_unify_type<'cx, 'tcx>(
     };
     debug!(?normalized, ?obligations, "project_and_unify_type result");
     let actual = obligation.predicate.term;
-    // For an example where this is neccessary see src/test/ui/impl-trait/nested-return-type2.rs
+    // For an example where this is necessary see src/test/ui/impl-trait/nested-return-type2.rs
     // This allows users to omit re-mentioning all bounds on an associated type and just use an
     // `impl Trait` for the assoc type to add more bounds.
     let InferOk { value: actual, obligations: new } =
@@ -566,7 +566,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                     .unwrap_or_else(|| ty.super_fold_with(self).into())
                 };
                 // For cases like #95134 we would like to catch overflows early
-                // otherwise they slip away away and cause ICE.
+                // otherwise they slip away and cause ICE.
                 let recursion_limit = self.tcx().recursion_limit();
                 if !recursion_limit.value_within_limit(self.depth)
                     // HACK: Don't overflow when running cargo doc see #100991
@@ -2254,7 +2254,10 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
     }
 
     let impl_fn_def_id = leaf_def.item.def_id;
-    let impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs);
+    // Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque},
+    // since `data.substs` are the impl substs.
+    let impl_fn_substs =
+        obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
 
     let cause = ObligationCause::new(
         obligation.cause.span,
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index af102952172..715f5be8e2f 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -11,10 +11,10 @@ use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::traits::Normalized;
-use rustc_middle::mir;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
+use rustc_span::DUMMY_SP;
 
 use std::ops::ControlFlow;
 
@@ -254,7 +254,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 let result = tcx.normalize_projection_ty(c_data)?;
                 // We don't expect ambiguity.
                 if result.is_ambiguous() {
-                    bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
+                    // 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(
@@ -297,7 +305,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 let result = tcx.normalize_projection_ty(c_data)?;
                 // We don't expect ambiguity.
                 if result.is_ambiguous() {
-                    bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
+                    // 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(
@@ -347,13 +363,6 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
         ))
     }
 
-    fn try_fold_mir_const(
-        &mut self,
-        constant: mir::ConstantKind<'tcx>,
-    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
-        constant.try_super_fold_with(self)
-    }
-
     #[inline]
     fn try_fold_predicate(
         &mut self,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index ddabea700d3..9ebff489201 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -676,19 +676,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
 
                 ty::PredicateKind::ConstEquate(c1, c2) => {
+                    assert!(
+                        self.tcx().features().generic_const_exprs,
+                        "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
+                    );
                     debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
 
-                    if self.tcx().features().generic_const_exprs {
-                        // FIXME: we probably should only try to unify abstract constants
-                        // if the constants depend on generic parameters.
-                        //
-                        // Let's just see where this breaks :shrug:
-                        if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
-                            (c1.kind(), c2.kind())
-                        {
-                            if self.infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
-                                return Ok(EvaluatedToOk);
-                            }
+                    // FIXME: we probably should only try to unify abstract constants
+                    // if the constants depend on generic parameters.
+                    //
+                    // Let's just see where this breaks :shrug:
+                    if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+                        (c1.kind(), c2.kind())
+                    {
+                        if self.infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
+                            return Ok(EvaluatedToOk);
                         }
                     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index fcb73b43fa8..63f89a33e8a 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -137,9 +137,8 @@ impl ChildrenExt<'_> for Children {
                     impl_def_id,
                     traits::SkipLeakCheck::default(),
                     overlap_mode,
-                    |_| true,
-                    || false,
-                );
+                )
+                .is_some();
 
                 let error = create_overlap_error(overlap);
 
@@ -162,34 +161,29 @@ impl ChildrenExt<'_> for Children {
                 impl_def_id,
                 traits::SkipLeakCheck::Yes,
                 overlap_mode,
-                |overlap| {
-                    if let Some(overlap_kind) =
-                        tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
-                    {
-                        match overlap_kind {
-                            ty::ImplOverlapKind::Permitted { marker: _ } => {}
-                            ty::ImplOverlapKind::Issue33140 => {
-                                *last_lint_mut = Some(FutureCompatOverlapError {
-                                    error: create_overlap_error(overlap),
-                                    kind: FutureCompatOverlapErrorKind::Issue33140,
-                                });
-                            }
+            )
+            .map_or(Ok((false, false)), |overlap| {
+                if let Some(overlap_kind) =
+                    tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
+                {
+                    match overlap_kind {
+                        ty::ImplOverlapKind::Permitted { marker: _ } => {}
+                        ty::ImplOverlapKind::Issue33140 => {
+                            *last_lint_mut = Some(FutureCompatOverlapError {
+                                error: create_overlap_error(overlap),
+                                kind: FutureCompatOverlapErrorKind::Issue33140,
+                            });
                         }
-
-                        return Ok((false, false));
                     }
 
-                    let le = tcx.specializes((impl_def_id, possible_sibling));
-                    let ge = tcx.specializes((possible_sibling, impl_def_id));
+                    return Ok((false, false));
+                }
 
-                    if le == ge {
-                        report_overlap_error(overlap, last_lint_mut)
-                    } else {
-                        Ok((le, ge))
-                    }
-                },
-                || Ok((false, false)),
-            )?;
+                let le = tcx.specializes((impl_def_id, possible_sibling));
+                let ge = tcx.specializes((possible_sibling, impl_def_id));
+
+                if le == ge { report_overlap_error(overlap, last_lint_mut) } else { Ok((le, ge)) }
+            })?;
 
             if le && !ge {
                 debug!(
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 5206e9f649b..ed47d2f83df 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -268,10 +268,7 @@ pub fn count_own_vtable_entries<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
 ) -> usize {
-    let existential_trait_ref =
-        trait_ref.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
-    let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
-    tcx.own_existential_vtable_entries(existential_trait_ref).len()
+    tcx.own_existential_vtable_entries(trait_ref.def_id()).len()
 }
 
 /// Given an upcast trait object described by `object`, returns the
@@ -282,15 +279,10 @@ pub fn get_vtable_index_of_object_method<'tcx, N>(
     object: &super::ImplSourceObjectData<'tcx, N>,
     method_def_id: DefId,
 ) -> Option<usize> {
-    let existential_trait_ref = object
-        .upcast_trait_ref
-        .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
-    let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
-
     // Count number of methods preceding the one we are selecting and
     // add them to the total offset.
     if let Some(index) = tcx
-        .own_existential_vtable_entries(existential_trait_ref)
+        .own_existential_vtable_entries(object.upcast_trait_ref.def_id())
         .iter()
         .copied()
         .position(|def_id| def_id == method_def_id)
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 635cdde0e8e..8908fe230b0 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -148,13 +148,8 @@ pub fn predicate_obligations<'tcx>(
             wf.compute(a.into());
             wf.compute(b.into());
         }
-        ty::PredicateKind::ConstEvaluatable(uv) => {
-            let obligations = wf.nominal_obligations(uv.def.did, uv.substs);
-            wf.out.extend(obligations);
-
-            for arg in uv.substs.iter() {
-                wf.compute(arg);
-            }
+        ty::PredicateKind::ConstEvaluatable(ct) => {
+            wf.compute(ct.into());
         }
         ty::PredicateKind::ConstEquate(c1, c2) => {
             wf.compute(c1.into());
@@ -219,7 +214,9 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
         trait_ref, item, cause, pred
     );
     let (items, impl_def_id) = match item {
-        Some(hir::Item { kind: hir::ItemKind::Impl(impl_), def_id, .. }) => (impl_.items, *def_id),
+        Some(hir::Item { kind: hir::ItemKind::Impl(impl_), owner_id, .. }) => {
+            (impl_.items, *owner_id)
+        }
         _ => return,
     };
     let fix_span =
@@ -241,7 +238,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
                     tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
                 && let Some(impl_item_span) = items
                     .iter()
-                    .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+                    .find(|item| item.id.owner_id.to_def_id() == impl_item_id)
                     .map(fix_span)
             {
                 cause.span = impl_item_span;
@@ -256,7 +253,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
                     tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id)
                 && let Some(impl_item_span) = items
                     .iter()
-                    .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+                    .find(|item| item.id.owner_id.to_def_id() == impl_item_id)
                     .map(fix_span)
             {
                 cause.span = impl_item_span;
@@ -308,32 +305,6 @@ impl<'tcx> WfPredicates<'tcx> {
         let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
             self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs)
         } else {
-            if !tcx.has_attr(trait_ref.def_id, rustc_span::sym::const_trait) {
-                if let Some(item) = self.item &&
-                   let hir::ItemKind::Impl(impl_) = item.kind &&
-                   let Some(trait_) = &impl_.of_trait &&
-                   let Some(def_id) = trait_.trait_def_id() &&
-                   def_id == trait_ref.def_id
-                {
-                    let trait_name = tcx.item_name(def_id);
-                    let mut err = tcx.sess.struct_span_err(
-                        self.span,
-                        &format!("const `impl` for trait `{trait_name}` which is not marked with `#[const_trait]`"),
-                    );
-                    if def_id.is_local() {
-                        let sp = tcx.def_span(def_id).shrink_to_lo();
-                        err.span_suggestion(sp, &format!("mark `{trait_name}` as const"), "#[const_trait]", rustc_errors::Applicability::MachineApplicable);
-                    }
-                    err.note("marking a trait with `#[const_trait]` ensures all default method bodies are `const`");
-                    err.note("adding a non-const method body in the future would be a breaking change");
-                    err.emit();
-                } else {
-                    tcx.sess.span_err(
-                        self.span,
-                        "~const can only be applied to `#[const_trait]` traits",
-                    );
-                }
-            }
             self.nominal_obligations(trait_ref.def_id, trait_ref.substs)
         };
 
@@ -476,14 +447,14 @@ impl<'tcx> WfPredicates<'tcx> {
                 // obligations are handled by the parent (e.g. `ty::Ref`).
                 GenericArgKind::Lifetime(_) => continue,
 
-                GenericArgKind::Const(constant) => {
-                    match constant.kind() {
+                GenericArgKind::Const(ct) => {
+                    match ct.kind() {
                         ty::ConstKind::Unevaluated(uv) => {
                             let obligations = self.nominal_obligations(uv.def.did, uv.substs);
                             self.out.extend(obligations);
 
                             let predicate =
-                                ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
+                                ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
                                     .to_predicate(self.tcx());
                             let cause = self.cause(traits::WellFormed(None));
                             self.out.push(traits::Obligation::with_depth(
@@ -500,7 +471,7 @@ impl<'tcx> WfPredicates<'tcx> {
                                 cause,
                                 self.recursion_depth,
                                 self.param_env,
-                                ty::Binder::dummy(ty::PredicateKind::WellFormed(constant.into()))
+                                ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into()))
                                     .to_predicate(self.tcx()),
                             ));
                         }
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 7d36b9558d5..82f6111f6f9 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -28,9 +28,9 @@ fn implied_outlives_bounds<'tcx>(
     &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
     NoSolution,
 > {
-    tcx.infer_ctxt().enter_canonical_trait_query(&goal, |infcx, _fulfill_cx, key| {
+    tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
         let (param_env, ty) = key.into_parts();
-        compute_implied_outlives_bounds(&infcx, param_env, ty)
+        compute_implied_outlives_bounds(&ocx.infcx, param_env, ty)
     })
 }
 
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index 0da28737f69..0ffa92f1ad5 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -3,6 +3,7 @@
 
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![feature(let_chains)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 58b718ed127..2da64d73d34 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -18,9 +18,6 @@ pub(crate) fn provide(p: &mut Providers) {
 
             try_normalize_after_erasing_regions(tcx, goal)
         },
-        try_normalize_mir_const_after_erasing_regions: |tcx, goal| {
-            try_normalize_after_erasing_regions(tcx, goal)
-        },
         ..*p
     };
 }
diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs
index 98bb42c9afd..e805eb42821 100644
--- a/compiler/rustc_traits/src/normalize_projection_ty.rs
+++ b/compiler/rustc_traits/src/normalize_projection_ty.rs
@@ -1,6 +1,5 @@
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
@@ -23,8 +22,8 @@ fn normalize_projection_ty<'tcx>(
     tcx.sess.perf_stats.normalize_projection_ty.fetch_add(1, Ordering::Relaxed);
     tcx.infer_ctxt().enter_canonical_trait_query(
         &goal,
-        |infcx, fulfill_cx, ParamEnvAnd { param_env, value: goal }| {
-            let selcx = &mut SelectionContext::new(infcx);
+        |ocx, ParamEnvAnd { param_env, value: goal }| {
+            let selcx = &mut SelectionContext::new(ocx.infcx);
             let cause = ObligationCause::dummy();
             let mut obligations = vec![];
             let answer = traits::normalize_projection_type(
@@ -35,7 +34,7 @@ fn normalize_projection_ty<'tcx>(
                 0,
                 &mut obligations,
             );
-            fulfill_cx.register_predicate_obligations(infcx, obligations);
+            ocx.register_obligations(obligations);
             // FIXME(associated_const_equality): All users of normalize_projection_ty expected
             // a type, but there is the possibility it could've been a const now. Maybe change
             // it to a Term later?
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index bca7458ed33..98cb3f21555 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -2,17 +2,14 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
-use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
-use rustc_infer::traits::{ObligationCauseCode, TraitEngineExt as _};
+use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{
-    self, EarlyBinder, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance,
-};
-use rustc_middle::ty::{GenericArg, UserSelfTy, UserSubsts};
-use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate};
+use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{ParamEnvAnd, Predicate, ToPredicate};
+use rustc_middle::ty::{UserSelfTy, UserSubsts};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
-use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::query::normalize::AtExt;
 use rustc_trait_selection::traits::query::type_op::ascribe_user_type::AscribeUserType;
 use rustc_trait_selection::traits::query::type_op::eq::Eq;
@@ -20,7 +17,7 @@ use rustc_trait_selection::traits::query::type_op::normalize::Normalize;
 use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate;
 use rustc_trait_selection::traits::query::type_op::subtype::Subtype;
 use rustc_trait_selection::traits::query::{Fallible, NoSolution};
-use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, TraitEngine};
+use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
 use std::fmt;
 use std::iter::zip;
 
@@ -42,17 +39,16 @@ fn type_op_ascribe_user_type<'tcx>(
     tcx: TyCtxt<'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
-    tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
-        type_op_ascribe_user_type_with_span(infcx, fulfill_cx, key, None)
+    tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
+        type_op_ascribe_user_type_with_span(ocx, key, None)
     })
 }
 
 /// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
 /// this query can be re-run to better track the span of the obligation cause, and improve the error
 /// message. Do not call directly unless you're in that very specific context.
-pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>(
-    infcx: &'a InferCtxt<'tcx>,
-    fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
+pub fn type_op_ascribe_user_type_with_span<'tcx>(
+    ocx: &ObligationCtxt<'_, 'tcx>,
     key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
     span: Option<Span>,
 ) -> Result<(), NoSolution> {
@@ -61,68 +57,50 @@ pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>(
         "type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
         mir_ty, def_id, user_substs
     );
-
-    let mut cx = AscribeUserTypeCx { infcx, param_env, span: span.unwrap_or(DUMMY_SP), fulfill_cx };
+    let cx = AscribeUserTypeCx { ocx, param_env, span: span.unwrap_or(DUMMY_SP) };
     cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?;
     Ok(())
 }
 
 struct AscribeUserTypeCx<'me, 'tcx> {
-    infcx: &'me InferCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    ocx: &'me ObligationCtxt<'me, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     span: Span,
-    fulfill_cx: &'me mut dyn TraitEngine<'tcx>,
 }
 
 impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
-    fn normalize<T>(&mut self, value: T) -> T
+    fn normalize<T>(&self, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
         self.normalize_with_cause(value, ObligationCause::misc(self.span, hir::CRATE_HIR_ID))
     }
 
-    fn normalize_with_cause<T>(&mut self, value: T, cause: ObligationCause<'tcx>) -> T
+    fn normalize_with_cause<T>(&self, value: T, cause: ObligationCause<'tcx>) -> T
     where
         T: TypeFoldable<'tcx>,
     {
-        self.infcx
-            .partially_normalize_associated_types_in(cause, self.param_env, value)
-            .into_value_registering_obligations(self.infcx, self.fulfill_cx)
+        self.ocx.normalize(cause, self.param_env, value)
     }
 
-    fn relate<T>(&mut self, a: T, variance: Variance, b: T) -> Result<(), NoSolution>
+    fn eq<T>(&self, a: T, b: T) -> Result<(), NoSolution>
     where
         T: ToTrace<'tcx>,
     {
-        self.infcx
-            .at(&ObligationCause::dummy_with_span(self.span), self.param_env)
-            .relate(a, variance, b)?
-            .into_value_registering_obligations(self.infcx, self.fulfill_cx);
-        Ok(())
+        Ok(self.ocx.eq(&ObligationCause::dummy_with_span(self.span), self.param_env, a, b)?)
     }
 
-    fn prove_predicate(&mut self, predicate: Predicate<'tcx>, cause: ObligationCause<'tcx>) {
-        self.fulfill_cx.register_predicate_obligation(
-            self.infcx,
-            Obligation::new(cause, self.param_env, predicate),
-        );
+    fn prove_predicate(&self, predicate: Predicate<'tcx>, cause: ObligationCause<'tcx>) {
+        self.ocx.register_obligation(Obligation::new(cause, self.param_env, predicate));
     }
 
     fn tcx(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn subst<T>(&self, value: T, substs: &[GenericArg<'tcx>]) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        EarlyBinder(value).subst(self.tcx(), substs)
+        self.ocx.infcx.tcx
     }
 
     #[instrument(level = "debug", skip(self))]
     fn relate_mir_and_user_ty(
-        &mut self,
+        &self,
         mir_ty: Ty<'tcx>,
         def_id: DefId,
         user_substs: UserSubsts<'tcx>,
@@ -130,20 +108,18 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
         let UserSubsts { user_self_ty, substs } = user_substs;
         let tcx = self.tcx();
 
-        let ty = tcx.type_of(def_id);
-        let ty = self.subst(ty, substs);
+        let ty = tcx.bound_type_of(def_id).subst(tcx, substs);
         let ty = self.normalize(ty);
         debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
 
-        self.relate(mir_ty, Variance::Invariant, ty)?;
+        self.eq(mir_ty, ty)?;
 
         // Prove the predicates coming along with `def_id`.
         //
         // Also, normalize the `instantiated_predicates`
         // because otherwise we wind up with duplicate "type
         // outlives" error messages.
-        let instantiated_predicates =
-            self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs);
+        let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
 
         let cause = ObligationCause::dummy_with_span(self.span);
 
@@ -163,15 +139,14 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
         }
 
         if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
-            let impl_self_ty = self.tcx().type_of(impl_def_id);
-            let impl_self_ty = self.subst(impl_self_ty, &substs);
+            let impl_self_ty = tcx.bound_type_of(impl_def_id).subst(tcx, substs);
             let impl_self_ty = self.normalize(impl_self_ty);
 
-            self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
+            self.eq(self_ty, impl_self_ty)?;
 
             self.prove_predicate(
                 ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()))
-                    .to_predicate(self.tcx()),
+                    .to_predicate(tcx),
                 cause.clone(),
             );
         }
@@ -188,7 +163,7 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
         // type were ill-formed but did not appear in `ty`,
         // which...could happen with normalization...
         self.prove_predicate(
-            ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()),
+            ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(tcx),
             cause,
         );
         Ok(())
@@ -199,19 +174,14 @@ fn type_op_eq<'tcx>(
     tcx: TyCtxt<'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
-    tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
+    tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
         let (param_env, Eq { a, b }) = key.into_parts();
-        infcx
-            .at(&ObligationCause::dummy(), param_env)
-            .eq(a, b)?
-            .into_value_registering_obligations(infcx, fulfill_cx);
-        Ok(())
+        Ok(ocx.eq(&ObligationCause::dummy(), param_env, a, b)?)
     })
 }
 
 fn type_op_normalize<'tcx, T>(
-    infcx: &InferCtxt<'tcx>,
-    fulfill_cx: &mut dyn TraitEngine<'tcx>,
+    ocx: &ObligationCtxt<'_, 'tcx>,
     key: ParamEnvAnd<'tcx, Normalize<T>>,
 ) -> Fallible<T>
 where
@@ -219,8 +189,8 @@ where
 {
     let (param_env, Normalize { value }) = key.into_parts();
     let Normalized { value, obligations } =
-        infcx.at(&ObligationCause::dummy(), param_env).normalize(value)?;
-    fulfill_cx.register_predicate_obligations(infcx, obligations);
+        ocx.infcx.at(&ObligationCause::dummy(), param_env).normalize(value)?;
+    ocx.register_obligations(obligations);
     Ok(value)
 }
 
@@ -256,13 +226,9 @@ fn type_op_subtype<'tcx>(
     tcx: TyCtxt<'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Subtype<'tcx>>>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
-    tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
+    tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
         let (param_env, Subtype { sub, sup }) = key.into_parts();
-        infcx
-            .at(&ObligationCause::dummy(), param_env)
-            .sup(sup, sub)?
-            .into_value_registering_obligations(infcx, fulfill_cx);
-        Ok(())
+        Ok(ocx.sup(&ObligationCause::dummy(), param_env, sup, sub)?)
     })
 }
 
@@ -274,8 +240,8 @@ fn type_op_prove_predicate<'tcx>(
     // impl-trait/issue-99642.rs
     tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter_canonical_trait_query(
         &canonicalized,
-        |infcx, fulfill_cx, key| {
-            type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy());
+        |ocx, key| {
+            type_op_prove_predicate_with_cause(ocx, key, ObligationCause::dummy());
             Ok(())
         },
     )
@@ -284,12 +250,11 @@ fn type_op_prove_predicate<'tcx>(
 /// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors,
 /// this query can be re-run to better track the span of the obligation cause, and improve the error
 /// message. Do not call directly unless you're in that very specific context.
-pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>(
-    infcx: &'a InferCtxt<'tcx>,
-    fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
+pub fn type_op_prove_predicate_with_cause<'tcx>(
+    ocx: &ObligationCtxt<'_, 'tcx>,
     key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>,
     cause: ObligationCause<'tcx>,
 ) {
     let (param_env, ProvePredicate { predicate }) = key.into_parts();
-    fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate));
+    ocx.register_obligation(Obligation::new(cause, param_env, predicate));
 }
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index acd4fa63d78..2bc6bc1fc23 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -284,7 +284,8 @@ pub(crate) mod rustc {
                 }
 
                 ty::Array(ty, len) => {
-                    let len = len.try_eval_usize(tcx, ParamEnv::reveal_all()).unwrap();
+                    let len =
+                        len.try_eval_usize(tcx, ParamEnv::reveal_all()).ok_or(Err::Unspecified)?;
                     let elt = Tree::from_ty(*ty, tcx)?;
                     Ok(std::iter::repeat(elt)
                         .take(len as usize)
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index f7cc94e5314..384d03106b1 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -122,7 +122,7 @@ mod rustc {
 
             let c = c.eval(tcx, param_env);
 
-            if let Some(err) = c.error_reported() {
+            if let Err(err) = c.error_reported() {
                 return Some(Self {
                     alignment: true,
                     lifetimes: true,
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 6e34ee21082..73c7eb6992f 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -4,6 +4,7 @@ use rustc_middle::ty::layout::{
     fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout,
 };
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::config::OptLevel;
 use rustc_span::def_id::DefId;
 use rustc_target::abi::call::{
     ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
@@ -384,7 +385,7 @@ fn fn_abi_new_uncached<'tcx>(
         conv,
         can_unwind: fn_can_unwind(cx.tcx(), fn_def_id, sig.abi),
     };
-    fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi)?;
+    fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi, fn_def_id)?;
     debug!("fn_abi_new_uncached = {:?}", fn_abi);
     Ok(cx.tcx.arena.alloc(fn_abi))
 }
@@ -394,6 +395,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
     cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
     fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>,
     abi: SpecAbi,
+    fn_def_id: Option<DefId>,
 ) -> Result<(), FnAbiError<'tcx>> {
     if abi == SpecAbi::Unadjusted {
         return Ok(());
@@ -404,7 +406,18 @@ fn fn_abi_adjust_for_abi<'tcx>(
         || abi == SpecAbi::RustIntrinsic
         || abi == SpecAbi::PlatformIntrinsic
     {
-        let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>| {
+        // Look up the deduced parameter attributes for this function, if we have its def ID and
+        // we're optimizing in non-incremental mode. We'll tag its parameters with those attributes
+        // as appropriate.
+        let deduced_param_attrs = if cx.tcx.sess.opts.optimize != OptLevel::No
+            && cx.tcx.sess.opts.incremental.is_none()
+        {
+            fn_def_id.map(|fn_def_id| cx.tcx.deduced_param_attrs(fn_def_id)).unwrap_or_default()
+        } else {
+            &[]
+        };
+
+        let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, arg_idx: Option<usize>| {
             if arg.is_ignore() {
                 return;
             }
@@ -451,10 +464,30 @@ fn fn_abi_adjust_for_abi<'tcx>(
                 // so we pick an appropriately sized integer type instead.
                 arg.cast_to(Reg { kind: RegKind::Integer, size });
             }
+
+            // If we deduced that this parameter was read-only, add that to the attribute list now.
+            //
+            // The `readonly` parameter only applies to pointers, so we can only do this if the
+            // argument was passed indirectly. (If the argument is passed directly, it's an SSA
+            // value, so it's implicitly immutable.)
+            if let (Some(arg_idx), &mut PassMode::Indirect { ref mut attrs, .. }) =
+                (arg_idx, &mut arg.mode)
+            {
+                // The `deduced_param_attrs` list could be empty if this is a type of function
+                // we can't deduce any parameters for, so make sure the argument index is in
+                // bounds.
+                if let Some(deduced_param_attrs) = deduced_param_attrs.get(arg_idx) {
+                    if deduced_param_attrs.read_only {
+                        attrs.regular.insert(ArgAttribute::ReadOnly);
+                        debug!("added deduced read-only attribute");
+                    }
+                }
+            }
         };
-        fixup(&mut fn_abi.ret);
-        for arg in fn_abi.args.iter_mut() {
-            fixup(arg);
+
+        fixup(&mut fn_abi.ret, None);
+        for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() {
+            fixup(arg, Some(arg_idx));
         }
     } else {
         fn_abi.adjust_for_foreign_abi(cx, abi)?;
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 3e2553c425e..424b52309d3 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -17,10 +17,10 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
     let item = tcx.hir().expect_item(def_id.expect_local());
     match item.kind {
         hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
-            trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
+            trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()),
         ),
         hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
-            impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
+            impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()),
         ),
         hir::ItemKind::TraitAlias(..) => &[],
         _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
@@ -46,7 +46,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
     match parent_item.kind {
         hir::ItemKind::Impl(ref impl_) => {
             if let Some(impl_item_ref) =
-                impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+                impl_.items.iter().find(|i| i.id.owner_id.to_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);
@@ -56,7 +56,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
 
         hir::ItemKind::Trait(.., ref trait_item_refs) => {
             if let Some(trait_item_ref) =
-                trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+                trait_item_refs.iter().find(|i| i.id.owner_id.to_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);
@@ -75,7 +75,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
 }
 
 fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
-    let def_id = trait_item_ref.id.def_id;
+    let owner_id = trait_item_ref.id.owner_id;
     let (kind, has_self) = match trait_item_ref.kind {
         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
@@ -85,15 +85,15 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty
     ty::AssocItem {
         name: trait_item_ref.ident.name,
         kind,
-        def_id: def_id.to_def_id(),
-        trait_item_def_id: Some(def_id.to_def_id()),
+        def_id: owner_id.to_def_id(),
+        trait_item_def_id: Some(owner_id.to_def_id()),
         container: ty::TraitContainer,
         fn_has_self_parameter: has_self,
     }
 }
 
 fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
-    let def_id = impl_item_ref.id.def_id;
+    let def_id = impl_item_ref.id.owner_id;
     let (kind, has_self) = match impl_item_ref.kind {
         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs
index 753c474a34b..c05eeb353a8 100644
--- a/compiler/rustc_ty_utils/src/errors.rs
+++ b/compiler/rustc_ty_utils/src/errors.rs
@@ -5,18 +5,18 @@ use rustc_middle::ty::Ty;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(ty_utils::needs_drop_overflow)]
+#[diag(ty_utils_needs_drop_overflow)]
 pub struct NeedsDropOverflow<'tcx> {
     pub query_ty: Ty<'tcx>,
 }
 
 #[derive(Diagnostic)]
-#[diag(ty_utils::generic_constant_too_complex)]
+#[diag(ty_utils_generic_constant_too_complex)]
 #[help]
 pub struct GenericConstantTooComplex {
     #[primary_span]
     pub span: Span,
-    #[note(ty_utils::maybe_supported)]
+    #[note(maybe_supported)]
     pub maybe_supported: Option<()>,
     #[subdiagnostic]
     pub sub: GenericConstantTooComplexSub,
@@ -24,46 +24,46 @@ pub struct GenericConstantTooComplex {
 
 #[derive(Subdiagnostic)]
 pub enum GenericConstantTooComplexSub {
-    #[label(ty_utils::borrow_not_supported)]
+    #[label(ty_utils_borrow_not_supported)]
     BorrowNotSupported(#[primary_span] Span),
-    #[label(ty_utils::address_and_deref_not_supported)]
+    #[label(ty_utils_address_and_deref_not_supported)]
     AddressAndDerefNotSupported(#[primary_span] Span),
-    #[label(ty_utils::array_not_supported)]
+    #[label(ty_utils_array_not_supported)]
     ArrayNotSupported(#[primary_span] Span),
-    #[label(ty_utils::block_not_supported)]
+    #[label(ty_utils_block_not_supported)]
     BlockNotSupported(#[primary_span] Span),
-    #[label(ty_utils::never_to_any_not_supported)]
+    #[label(ty_utils_never_to_any_not_supported)]
     NeverToAnyNotSupported(#[primary_span] Span),
-    #[label(ty_utils::tuple_not_supported)]
+    #[label(ty_utils_tuple_not_supported)]
     TupleNotSupported(#[primary_span] Span),
-    #[label(ty_utils::index_not_supported)]
+    #[label(ty_utils_index_not_supported)]
     IndexNotSupported(#[primary_span] Span),
-    #[label(ty_utils::field_not_supported)]
+    #[label(ty_utils_field_not_supported)]
     FieldNotSupported(#[primary_span] Span),
-    #[label(ty_utils::const_block_not_supported)]
+    #[label(ty_utils_const_block_not_supported)]
     ConstBlockNotSupported(#[primary_span] Span),
-    #[label(ty_utils::adt_not_supported)]
+    #[label(ty_utils_adt_not_supported)]
     AdtNotSupported(#[primary_span] Span),
-    #[label(ty_utils::pointer_not_supported)]
+    #[label(ty_utils_pointer_not_supported)]
     PointerNotSupported(#[primary_span] Span),
-    #[label(ty_utils::yield_not_supported)]
+    #[label(ty_utils_yield_not_supported)]
     YieldNotSupported(#[primary_span] Span),
-    #[label(ty_utils::loop_not_supported)]
+    #[label(ty_utils_loop_not_supported)]
     LoopNotSupported(#[primary_span] Span),
-    #[label(ty_utils::box_not_supported)]
+    #[label(ty_utils_box_not_supported)]
     BoxNotSupported(#[primary_span] Span),
-    #[label(ty_utils::binary_not_supported)]
+    #[label(ty_utils_binary_not_supported)]
     BinaryNotSupported(#[primary_span] Span),
-    #[label(ty_utils::logical_op_not_supported)]
+    #[label(ty_utils_logical_op_not_supported)]
     LogicalOpNotSupported(#[primary_span] Span),
-    #[label(ty_utils::assign_not_supported)]
+    #[label(ty_utils_assign_not_supported)]
     AssignNotSupported(#[primary_span] Span),
-    #[label(ty_utils::closure_and_return_not_supported)]
+    #[label(ty_utils_closure_and_return_not_supported)]
     ClosureAndReturnNotSupported(#[primary_span] Span),
-    #[label(ty_utils::control_flow_not_supported)]
+    #[label(ty_utils_control_flow_not_supported)]
     ControlFlowNotSupported(#[primary_span] Span),
-    #[label(ty_utils::inline_asm_not_supported)]
+    #[label(ty_utils_inline_asm_not_supported)]
     InlineAsmNotSupported(#[primary_span] Span),
-    #[label(ty_utils::operation_not_supported)]
+    #[label(ty_utils_operation_not_supported)]
     OperationNotSupported(#[primary_span] Span),
 }
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 416c1ec510b..6436713b388 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -4,7 +4,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::traits::CodegenObligationError;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitable};
-use rustc_span::{sym, DUMMY_SP};
+use rustc_span::sym;
 use rustc_trait_selection::traits;
 use traits::{translate_substs, Reveal};
 
@@ -236,7 +236,7 @@ fn resolve_associated_item<'tcx>(
                 if name == sym::clone {
                     let self_ty = trait_ref.self_ty();
 
-                    let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env);
+                    let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env);
                     match self_ty.kind() {
                         _ if is_copy => (),
                         ty::Generator(..)
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 345911f4309..52ba0eee97c 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -399,7 +399,7 @@ fn layout_of_uncached<'tcx>(
             }
 
             let pointee = tcx.normalize_erasing_regions(param_env, pointee);
-            if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
+            if pointee.is_sized(tcx, param_env) {
                 return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
             }
 
@@ -755,8 +755,7 @@ fn layout_of_uncached<'tcx>(
                 } else {
                     let param_env = tcx.param_env(def.did());
                     let last_field = def.variant(v).fields.last().unwrap();
-                    let always_sized =
-                        tcx.type_of(last_field.did).is_sized(tcx.at(DUMMY_SP), param_env);
+                    let always_sized = tcx.type_of(last_field.did).is_sized(tcx, param_env);
                     if !always_sized { StructKind::MaybeUnsized } else { StructKind::AlwaysSized }
                 };
 
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index ba987c6f763..024dcd591bd 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -109,7 +109,7 @@ where
 
             for component in components {
                 match *component.kind() {
-                    _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (),
+                    _ if component.is_copy_modulo_regions(tcx, self.param_env) => (),
 
                     ty::Closure(_, substs) => {
                         queue_type(self, substs.as_closure().tupled_upvars_ty());
@@ -264,7 +264,7 @@ fn adt_consider_insignificant_dtor<'tcx>(
         if is_marked_insig {
             // In some cases like `std::collections::HashMap` where the struct is a wrapper around
             // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies
-            // outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with
+            // outside stdlib, we might choose to still annotate the wrapper (std HashMap) with
             // `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl.
             Some(DtorType::Insignificant)
         } else if adt_def.destructor(tcx).is_some() {
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 196d70614e7..99d3bda6ebf 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -137,10 +137,82 @@ 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(consts): This is not exactly in line with the constness query.
+    let constness = match hir_id {
+        Some(hir_id) => match tcx.hir().get(hir_id) {
+            hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
+                if tcx.is_const_default_method(def_id) =>
+            {
+                hir::Constness::Const
+            }
+
+            hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. })
+            | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. })
+            | hir::Node::TraitItem(hir::TraitItem {
+                kind: hir::TraitItemKind::Const(..), ..
+            })
+            | hir::Node::AnonConst(_)
+            | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
+            | hir::Node::ImplItem(hir::ImplItem {
+                kind:
+                    hir::ImplItemKind::Fn(
+                        hir::FnSig {
+                            header: hir::FnHeader { constness: hir::Constness::Const, .. },
+                            ..
+                        },
+                        ..,
+                    ),
+                ..
+            }) => hir::Constness::Const,
+
+            hir::Node::ImplItem(hir::ImplItem {
+                kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..),
+                ..
+            }) => {
+                let parent_hir_id = tcx.hir().get_parent_node(hir_id);
+                match tcx.hir().get(parent_hir_id) {
+                    hir::Node::Item(hir::Item {
+                        kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
+                        ..
+                    }) => *constness,
+                    _ => span_bug!(
+                        tcx.def_span(parent_hir_id.owner),
+                        "impl item's parent node is not an impl",
+                    ),
+                }
+            }
+
+            hir::Node::Item(hir::Item {
+                kind:
+                    hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..),
+                ..
+            })
+            | hir::Node::TraitItem(hir::TraitItem {
+                kind:
+                    hir::TraitItemKind::Fn(
+                        hir::FnSig { header: hir::FnHeader { constness, .. }, .. },
+                        ..,
+                    ),
+                ..
+            })
+            | hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
+                ..
+            }) => *constness,
+
+            _ => hir::Constness::NotConst,
+        },
+        // FIXME(consts): It's suspicious that a param-env for a foreign item
+        // will always have NotConst param-env, though we don't typically use
+        // that param-env for anything meaningful right now, so it's likely
+        // not an issue.
+        None => hir::Constness::NotConst,
+    };
+
     let unnormalized_env = ty::ParamEnv::new(
         tcx.intern_predicates(&predicates),
         traits::Reveal::UserFacing,
-        tcx.constness(def_id),
+        constness,
     );
 
     let body_id =
@@ -341,7 +413,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<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());
-    if let Some(fn_kind) = node.fn_kind() { fn_kind.asyncness() } else { hir::IsAsync::NotAsync }
+    node.fn_sig().map_or(hir::IsAsync::NotAsync, |sig| sig.header.asyncness)
 }
 
 /// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead.
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index da30344ef7e..7c3eb4efbc9 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -45,7 +45,7 @@ pub trait Interner {
     type BoundTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
     type PlaceholderType: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
     type InferTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
-    type DelaySpanBugEmitted: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type ErrorGuaranteed: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
     type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
     type AllocId: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
 
@@ -675,9 +675,9 @@ impl<CTX> HashStable<CTX> for InferTy {
         use InferTy::*;
         discriminant(self).hash_stable(ctx, hasher);
         match self {
-            TyVar(v) => v.as_u32().hash_stable(ctx, hasher),
-            IntVar(v) => v.index.hash_stable(ctx, hasher),
-            FloatVar(v) => v.index.hash_stable(ctx, hasher),
+            TyVar(_) | IntVar(_) | FloatVar(_) => {
+                panic!("type variables should not be hashed: {self:?}")
+            }
             FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher),
         }
     }
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
index 6d54924e515..02cbb2e858f 100644
--- a/compiler/rustc_type_ir/src/sty.rs
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -217,7 +217,7 @@ pub enum TyKind<I: Interner> {
 
     /// A placeholder for a type which could not be computed; this is
     /// propagated to avoid useless error messages.
-    Error(I::DelaySpanBugEmitted),
+    Error(I::ErrorGuaranteed),
 }
 
 impl<I: Interner> TyKind<I> {
@@ -626,7 +626,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
 // This is manually implemented because a derive would require `I: Encodable`
 impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I>
 where
-    I::DelaySpanBugEmitted: Encodable<E>,
+    I::ErrorGuaranteed: Encodable<E>,
     I::AdtDef: Encodable<E>,
     I::SubstsRef: Encodable<E>,
     I::DefId: Encodable<E>,
@@ -645,7 +645,6 @@ where
     I::BoundTy: Encodable<E>,
     I::PlaceholderType: Encodable<E>,
     I::InferTy: Encodable<E>,
-    I::DelaySpanBugEmitted: Encodable<E>,
     I::PredicateKind: Encodable<E>,
     I::AllocId: Encodable<E>,
 {
@@ -744,7 +743,7 @@ where
 // This is manually implemented because a derive would require `I: Decodable`
 impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for TyKind<I>
 where
-    I::DelaySpanBugEmitted: Decodable<D>,
+    I::ErrorGuaranteed: Decodable<D>,
     I::AdtDef: Decodable<D>,
     I::SubstsRef: Decodable<D>,
     I::DefId: Decodable<D>,
@@ -763,7 +762,6 @@ where
     I::BoundTy: Decodable<D>,
     I::PlaceholderType: Decodable<D>,
     I::InferTy: Decodable<D>,
-    I::DelaySpanBugEmitted: Decodable<D>,
     I::PredicateKind: Decodable<D>,
     I::AllocId: Decodable<D>,
 {
@@ -829,7 +827,7 @@ where
     I::ParamTy: HashStable<CTX>,
     I::PlaceholderType: HashStable<CTX>,
     I::InferTy: HashStable<CTX>,
-    I::DelaySpanBugEmitted: HashStable<CTX>,
+    I::ErrorGuaranteed: HashStable<CTX>,
 {
     #[inline]
     fn hash_stable(
@@ -1332,8 +1330,8 @@ where
             RePlaceholder(p) => {
                 p.hash_stable(hcx, hasher);
             }
-            ReVar(reg) => {
-                reg.hash_stable(hcx, hasher);
+            ReVar(_) => {
+                panic!("region variables should not be hashed: {self:?}")
             }
         }
     }